Wawk engine extends AWK — the classic pattern-scanning and text-processing language created at Bell Labs — on WebAssembly with plugin extensibility. It produces no native binaries — every component compiles to .wasm modules that run in browsers, on servers, and at the edge with identical output everywhere.
wawk consists of wawk-core as the shared engine, wawk-wasi as a pure WASI command-line module, and wawk-bindgen as a JavaScript-importable library. All three share the same engine code and produce identical output for the same input. Extensions are built as WIT Component Model plugins — standalone .wasm modules that are loaded explicitly via the --plugin flag.
# Build$ cargo build -p wawk-wasi --target wasm32-wasip1 --release# Sum a column$ printf '{ sum += $1 } END { print sum }\n1\n2\n3\n' \ | wasmtime target/wasm32-wasip1/release/wawk-wasi.wasm6# Filter lines matching a pattern$ printf '/error/ { print $0 }\ninfo: ok\nerror: disk full\n' \ | wasmtime target/wasm32-wasip1/release/wawk-wasi.wasmerror: disk full
Use wawk-bindgen in Node.js
# Build for Node.js$ wasm-pack build crates/wawk-bindgen \ --target nodejs \ --out-dir ../../pkg-node \ --release# Run the end-to-end test$ node crates/wawk-bindgen/tests/node_e2e.js
Use wawk-bindgen in the browser
# Build for the browser$ wasm-pack build crates/wawk-bindgen \ --target web \ --out-dir ../../pkg-web \ --release# Open pkg-web/test.html in a browser
Background
AWK History
AWK is a text-processing language created at Bell Labs. It reads input line by line, matches patterns, and executes actions. It is part of the POSIX standard and has been shipped with every Unix system since the late 1970s.
1977
AWK is created
Alfred Aho, Peter Weinberger, and Brian Kernighan develop AWK at Bell Labs. The name comes from their initials.
1988
The AWK Programming Language published
The authors publish a book covering the language in depth, including associative arrays and regular expressions.
1990s
POSIX standardization
AWK is included in the POSIX standard. Multiple implementations exist: gawk, mawk, nawk, and the original awk.
2026
AWK reinvented in Rust and Wasm
AWK reimplemented in Rust, compiled to Wasm. Runs in browsers and edge runtimes with no OS dependencies.
What AWK is used for
AWK is a general-purpose text processing tool. Common uses include:
Log analysis
Filter, count, and aggregate entries from server logs and structured text streams.
CSV / TSV processing
Extract columns, reshape rows, convert between delimited formats.
Text transformation
Regex-driven rewriting, format conversion, structured extraction from unstructured text.
Reporting
One-pass counting, summing, grouping, and summary generation.
How Wawk Extends AWK
Wawk carries AWK's proven text-processing model into new environments that were not available when AWK was created:
Browser-based data processing
Run AWK directly in the browser — no server required. Build interactive log analyzers and data explorers as client-side web apps.
Edge computing & serverless
Deploy AWK to edge runtimes and serverless platforms. Process data at the edge with zero cold starts and sandboxed execution.
AI agent tool integration
Use AWK as a programmable data-transform layer in AI agent workflows. Pipe data between tools and models with a familiar syntax.
Extensible via WIT Component Model plugins
Add custom functions (greetings, encoding, validation) via WIT plugins — build once as a .wasm component, loaded via --plugin in any host (browser, Node.js, Wasmtime).
Extensions
AWK → Wawk
AWK has done its job remarkably well for nearly five decades. Wawk builds on that foundation, adding capabilities that the WebAssembly platform makes possible — without changing the AWK language itself.
Scenario
AWK (system-installed)
Wawk (Wasm)
Run in browser
Outside the browser's scope
Native Wasm execution
Deploy to edge
Designed for server-based pipelines
Edge runtimes, serverless
Custom functions
C extensions (gawk)
Wasm extensions (Rust, C, Go)
Sandboxing
OS-level isolation
Wasm runtime sandbox
Distribution
Pre-installed on Unix systems
Single .wasm file
Cross-platform consistency
Multiple implementations (gawk, mawk, nawk)
Identical output everywhere
Tutorial
Interactive AWK Tutorial
Edit the script and input below, then press Run. The AWK engine executes in your browser as real WebAssembly via wawk-bindgen.
Chapter 1Pattern & Action
Loading Wasm...
script.awk
input.txt
stdout
Press Run to execute
1 / 6
Plugin Development
Build Your First Plugin
Wawk plugins extend AWK with custom functions using the WIT Component Model. A plugin is a standalone .wasm file that exports the wawk:plugins/external-functions interface. Build once — the same plugin works in wasmtime, Node.js, and the browser with zero changes.
Build target
wasm32-unknown-unknown
Plugin size
~60 KB typical
Configuration
--plugin flag
Languages
Rust, C, C++, Go, TS
How Plugins Work
When the AWK evaluator encounters a function call it does not recognise as built-in or user-defined, it iterates through loaded plugins. Each plugin receives the function name and arguments via the WIT canonical ABI. A plugin returns some(result) if it handles the function, or none to pass to the next plugin.
1
AWK script calls greet("World") — the evaluator does not recognise greet as built-in.
2
Host encodes the call via WIT canonical ABI and invokes wawk:plugins/external-functions#call on each loaded plugin.
3
Plugin matches the function name, builds a greeting, and returns some("Hello, World!").
4
Host decodes the result and feeds it back to the AWK evaluator as the function return value.
Step 1: Define the WIT Interface
Copy the canonical WIT world into your plugin’s wit/ directory. This is the contract between your plugin and every wawk host.
// wit/world.witpackage wawk:plugins;
interfaceexternal-functions {
/// Dispatch a function call with string arguments./// Return some(result) if handled, none to pass through.
call: func(name: string, args: list<string>) -> option<string>;
}
worldwawk-plugin {
exportexternal-functions;
}
Step 2: Implement the Plugin
Use wit-bindgen to generate Rust exports from the WIT definition. Implement the Guest trait — match on function names and return Some(result) or None.
// src/lib.rs// Generate WIT exports from wit/world.wit
wit_bindgen::generate!({
world: "wawk-plugin",
path: "wit",
});
structComponent;
impl exports::wawk::plugins::external_functions::GuestforComponent {
fncall(name: String, args: Vec<String>) -> Option<String> {
match name.as_str() {
"greet" => {
let who = args.first()
.map(|s| s.as_str())
.unwrap_or("World");
Some(format!("Hello, {}!", who))
}
_ => None, // unknown function — pass to next plugin
}
}
}
export!(Component);
Step 3: Build the Plugin
Compile to wasm32-unknown-unknown. The output is a single .wasm file. Load it with --plugin — no manifest files, no registration code.
# Build the plugin$ cargo build --target wasm32-unknown-unknown --release# Output: target/wasm32-unknown-unknown/release/my_plugin.wasm# Load with --plugin flag or copy to plugins/ for Node.js$ cp target/wasm32-unknown-unknown/release/my_plugin.wasm plugins/
Step 4: Use in AWK Scripts
Once built, load the plugin .wasm using the --plugin flag (wawk CLI) or place it in the plugins/ directory (Node.js). Your functions are then available in AWK scripts.
The wit-bindgen toolchain generates core WebAssembly exports that follow the WIT canonical ABI. Hosts (Node.js, browser, wasmtime) call these exports directly — no additional tooling required at runtime.
Export
Purpose
wawk:plugins/external-functions#call
String ABI — receives function name and string arguments, returns optional string result
cabi_realloc
Standard WIT memory allocation (old_ptr, old_size, align, new_size) → new_ptr
cabi_post_*#call
Cleanup function called by the host after reading the result
Key design principles
Build once, run anywhere — the same .wasm file works under wasmtime, Node.js, and in the browser.
Explicit loading — load plugins via --plugin flag in the CLI, or place in plugins/ for Node.js. No manifest or registration code needed.
Standard WIT — uses the WIT Component Model canonical ABI. No proprietary protocol.
Return None for unknown functions — the host tries the next plugin before reporting “unknown function”.
String ABI — the call function handles all plugin dispatch via string arguments.
Contact
Feedback
Questions, bug reports, or suggestions? Send us an email at team [at] ailur.ai.