Wawk — AWK, Extended

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.

Runtime
Browser, Server, Edge
Language
100% Rust → Wasm
OS Dependencies
None
License
MIT / Apache 2.0

Getting Started

Prerequisites

# Install Wasmtime (for wawk-wasi) $ curl https://wasmtime.dev/install.sh -sSf | bash # Install wasm-pack (for wawk-bindgen) $ cargo install wasm-pack

Build all Wasm targets

$ make build-wasm

Run wawk-wasi

# 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.wasm 6 # Filter lines matching a pattern $ printf '/error/ { print $0 }\ninfo: ok\nerror: disk full\n' \ | wasmtime target/wasm32-wasip1/release/wawk-wasi.wasm error: 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

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).

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

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 1 Pattern & Action
Loading Wasm...
script.awk
input.txt
stdout
Press Run to execute
1 / 6

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.wit package wawk:plugins; interface external-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>; } world wawk-plugin { export external-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", }); struct Component; impl exports::wawk::plugins::external_functions::Guest for Component { fn call(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.

# Cargo.toml — minimal dependencies [lib] crate-type = ["cdylib"] [dependencies] wit-bindgen = "0.42"
# 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.

# wawk CLI — load plugin via --plugin flag $ wawk --plugin ./my_plugin.wasm 'BEGIN { print greet("World") }' Hello, World! # Node.js — copy to plugins/ directory $ cp my_plugin.wasm plugins/ $ node run/run.js 'BEGIN { print greet("World") }' Hello, World! # Pipe input data $ echo "AWK" | wawk --plugin ./my_plugin.wasm '{ print greet($0) }' Hello, AWK!

WIT Canonical ABI Reference

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.

Feedback

Questions, bug reports, or suggestions? Send us an email at .

You can also find us on GitHub or visit our website.