# Walrus: a Rust library for rewriting WebAssembly modules

> Walrus is the WebAssembly transformation library behind the wasm-bindgen CLI, a Rust crate that lets you parse a module, rewrite its functions and imports, and emit it again. It is a plumbing tool rather than a product, and its value shows up when the toolchain has to rewrite a module in ways the source language cannot express.

**wasm-bindgen/walrus** — Walrus is a WebAssembly transformation library 🌊🐘

- Repository: https://github.com/wasm-bindgen/walrus
- Website: https://docs.rs/walrus
- Stars: 528 · Forks: 87
- Language: Rust
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/wasm-bindgen-walrus

## The library that rewrites modules rather than compiling them

Walrus is described in the readme as a Rust library for performing WebAssembly transformations in a way that is meant to be ergonomic and dependable, and the repository description is shorter: a WebAssembly transformation library.

The word transformation is doing the work. A compiler turns source into a module. Walrus takes a module that already exists and changes it, and then writes it back out. That is a different job with different users. The people who need it are toolchain authors: the people who build the bindings, the bundlers, the minifiers, the profilers.

The proof of use is in the readme. The crate is currently used to power the wasm-bindgen CLI tool and its own internal transformations. That is a significant amount of real use, and it also tells you the shape of the API, because a CLI that has to rewrite a module for a binding generator needs exactly the operations Walrus provides.

The readme is candid about the maturity, saying the crate is still in its early days, and then immediately undercuts that by describing a long term goal: using Walrus will, in the long term, also allow transforming WebAssembly while preserving DWARF debug information to ensure that debugging the final module is just as nice as debugging the intermediate module.

That goal is worth understanding because it explains a lot about the design. If you can rewrite a module and keep the debug information, then the transformation step stops being a boundary in your debugging workflow. Today a rewritten module loses its debug info, and you step from your Rust source into the generated module blind. The gimli dependency in the manifest is a clue that the DWARF side is not aspirational.

The project is built with the Rust and WebAssembly Working Group, and the readme links the API documentation on docs.rs, a contributing guide and a chat channel.

## The dependency set tells you what the library actually does

The Cargo.toml is short and every dependency has a job, which makes it the most efficient way to understand the architecture.

wasmparser at 0.245.1 is the parser, and wasm-encoder at 0.245.1 is the encoder. Those two are the same version, and that is a design decision rather than a coincidence. A transformation library has to read a module and write a module, and if the parser and the encoder disagree about the format specification, you get subtle corruptions in the output. Pinning them to the same version means the round trip is coherent by construction.

leb128 handles the LEB128 variable length integer encoding the WebAssembly binary format uses for lengths and indices. The id-arena crate provides an arena allocator, and id-arena is a fork of the arena crate that supports the parallel feature. gimli at 0.32.0 is a DWARF parsing library, and it is the dependency that ties back to the debug information goal in the readme.

anyhow and log are the error handling and logging faces. walrus-macro is a procedural macro crate kept in the same repository at crates/macro, pinned to an exact version, which is how the library provides its more declarative interface.

The one optional dependency is rayon, and it is behind a feature flag.

```toml
[features]
parallel = ['rayon', 'id-arena/rayon']
```

So parallel transformation is opt in, and enabling it changes the arena implementation rather than just adding a thread pool. That is a notable detail: an arena allocator that hands out references to its contents is not trivially thread safe, and the id-arena fork exists to make it so. The alternative, a single threaded build with no rayon in the tree at all, is what a build for a small target or a deterministic environment would want.

The workspace members are the macro crate, the tests crate, a tests-utils crate and a fuzz-utils crate, so fuzzing is part of the project rather than an afterthought. There is a fuzz/ directory at the root and a benches/ directory, with a criterion benchmark declared in the manifest, and the library target itself has bench set to false because the benches live in their own target.

## Three example programs, and what they are for

The examples directory has three programs, and between them they cover the three things you would want to do with a transformation library.

The readme points at examples/build-wasm-from-scratch.rs as a quick intro to building a Wasm module from scratch with walrus. That is the interesting one, because it is not a transformation at all. It is a construction, where you emit a module from nothing, which is what you need if you are writing a tool that produces WebAssembly rather than one that rewrites it.

Then there is examples/parse.rs and examples/round-trip.rs, and the names describe what they do. Parsing is the entry point to everything else, since a transformation cannot begin until the module is in memory as a structure the library can query and modify. The round trip is the critical correctness test for this kind of library: read a module, write it back, and check that the output is the same module. A transformation library whose encoder does not reproduce the parser's view of the format is a library that corrupts modules, and a round trip example is the cheapest possible guard against that.

The readme also points at wasm-snip as a relatively simple and self contained but still Real World example of using walrus, and that phrasing tells you the intended audience. The in-tree examples are introductions, and the real demonstration is a separate project, which is how you would want a library that has moved past its early days to present itself.

The publish.sh script and the .gitmodules entry sit in the root alongside the source, src/. The manifest also lists a categories field of just wasm, and the description is the single line A library for performing WebAssembly transformations.

The version numbers tell a story of their own. The recent releases are 0.27.1 from 2026-09-10, 0.27.0 from 2026-09-08 and 0.26.5 from 2026-08-18, and the manifest in the repository lists version 0.27.2. The last push was on 2026-10-20, so the crate is still moving at roughly a patch per month with occasional minor bumps, and the 0.x version means the public API is not yet frozen.

## The repository is small, and the layout says what is missing

The top level listing is short enough to read in one pass, and it describes a focused library rather than a large toolchain.

There is a src/ directory for the library itself, a crates/ directory for the internal sub-crates, examples/, benches/ and a fuzz/ directory. There is an AGENTS.md file, which tells you the project expects work to be done with an AI assistant in the loop, and a CHANGELOG.md, CONTRIBUTING.md, a publish.sh script and a .gitmodules file.

The .gitmodules entry is worth a note, because the manifest lists the macro crate as a path dependency at ./crates/macro with an exact version requirement of =0.26.0, and the workspace members list includes ./crates/macro alongside ./crates/fuzz-utils, ./crates/tests and ./crates/tests-utils. So the macro is developed in lockstep with the library rather than published separately, and the tests and fuzzing utilities are workspace members too, which means they are versioned with the crate.

The Cargo.toml also carries the fields a published crate needs: categories of just wasm, the repository and homepage URLs pointing at the rustwasm organisation, the documentation link to docs.rs, and the license field as MIT/Apache-2.0. The package version in the manifest is 0.27.2 while the most recent listed release is 0.27.1, so the tree is a little ahead of the last tag, which is normal for a repository that develops on main.

What is not in the tree is as telling as what is. There is no directory of built-in transformations for common tasks, no command line binary of its own, and no configuration file format. The library is the product, and the wasm-bindgen CLI is the demonstration of what a consumer looks like.

## Where Walrus is the wrong tool

There are three cases where this is the wrong choice, and they are all cases where the job is not really a transformation.

The first is calling a WebAssembly function from your own language. That is a binding generator's job, and it is what wasm-bindgen does. Walrus is the layer underneath such a generator, not the layer you use. If you want to call a Rust function from JavaScript, you want the binding generator, and you would use Walrus only if you were writing one.

The second is compiling. Walrus does not compile Rust to WebAssembly, and it is not a toolchain in the sense that rustc or wasm-pack are. The readme's example of building a Wasm module from scratch shows that the library can emit modules, but that is construction for tooling purposes, not a replacement for a compiler front end.

The third is a project where the transformation is simple enough to do with text processing on the binary or with a different tool entirely. A module that only needs its import names rewritten might be handled by a much smaller tool. Walrus earns its complexity when you need to manipulate the module's structure: add functions, change signatures, rewrite bodies, add or remove imports, and have the result still be a valid module.

The real limitations are in the documentation rather than the code. The readme is short, and it says so itself with a Stay tuned for more information in the future. It does not enumerate which parts of the WebAssembly specification are supported, how the library handles features such as reference types, bulk memory or SIMD, or what its behaviour is on a module it cannot fully represent. The DWARF preservation goal is explicitly framed as a long term one, which means today you should assume the debug information is not preserved.

There is also a version coupling to plan around. Walrus pins wasmparser and wasm-encoder to the same 0.245.1 release, and the crate releases follow the WebAssembly specification and those crates closely. A project that needs to consume a module produced by a newer toolchain, or one that depends on a different version of wasmparser for its own reasons, will find the versions do not line up.

On the alternative, the difference in approach against a lower level parser is the difference between a data structure and a byte stream. A raw parser gives you the bytes and lets you write them back yourself, which means you own the encoder, the ordering rules, the index spaces and every detail of the binary format, and a mistake in any of them produces a module that fails to validate. Walrus owns that layer, so you work with modules, functions, types and imports as objects with a query and edit API, and the library takes care of renumbering and re-encoding. The trade is that you accept the library's model of what a module is, including the parts it does not yet model, and that model is where the constraint on using it for a newer specification comes from.

The licence is worth a sentence, because it is unusually accommodating. The project is licensed under either of the Apache License, Version 2.0 or the MIT license, at your option, and the contribution terms say that unless you explicitly state otherwise, any contribution intentionally submitted for inclusion shall be dual licensed as above, without any additional terms or conditions. That is a clean, standard dual licence with no unusual conditions attached.

## Conclusion

Walrus suits a toolchain author who needs to inspect and rewrite a WebAssembly module programmatically, for example to rename imports or reshape a function body, and it does not suit an application developer who just wants to call a WebAssembly function from their language, since that is a binding generator's job. Before you depend on it, check the version you pin against your wasmparser and wasm-encoder versions, because the manifest ties them to 0.245.1 and the crate tracks those closely, and note the licence is MIT or Apache-2.0 at your option, with contributions dual licensed on the same terms.

## FAQ

### What is the Walrus crate?

Walrus is a Rust library for performing WebAssembly transformations, meaning it parses an existing module, lets you rewrite it, and writes it back out. It is used to power the wasm-bindgen CLI tool and its own internal transformations.

### What does the Walrus crate depend on?

The manifest lists wasmparser and wasm-encoder, both at version 0.245.1, along with id-arena, leb128, anyhow, log, gimli for DWARF handling and a walrus-macro procedural macro crate kept in the same repository. Rayon is optional behind the parallel feature.

### Does Walrus support parallel transformation?

Yes, through the parallel feature, which enables rayon and switches id-arena to its rayon-enabled implementation. The feature is opt in, so a single threaded build does not pull rayon into the dependency tree.

### Does Walrus preserve DWARF debug information?

The readme describes preserving DWARF debug information while transforming WebAssembly as a long term goal, so today you should not assume debug information survives a transformation. The gimli dependency is present in the manifest.

### What licence is the Walrus crate under?

It is licensed under either the Apache License, Version 2.0 or the MIT license, at your option, and contributions are dual licensed on the same terms unless the contributor states otherwise.

## Sources

- [License: Apache-2.0](https://github.com/wasm-bindgen/walrus/blob/main/LICENSE)
- [Project website](https://docs.rs/walrus)
- [README](https://github.com/wasm-bindgen/walrus/blob/main/README.md)
- [Releases](https://github.com/wasm-bindgen/walrus/releases)
- [wasm-bindgen/walrus on GitHub](https://github.com/wasm-bindgen/walrus)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/wasm-bindgen-walrus
