wasm-pack: building Rust to WebAssembly packages for npm
📦✨ your favorite rust -> wasm workflow tool!
At a glance
- What is it?
- wasm-pack wraps cargo, wasm-bindgen and wasm-opt into one CLI that turns a Rust crate into an npm package. It is the shortest path from Rust to a browser or Node.js import, and it is also a tool with opinions about your project layout.
- Who is it for?
- Adopt wasm-pack when your output is a JavaScript-consumable npm package and you want cargo, wasm-bindgen and packaging handled in one command; the README's own framing is a one-stop shop for Rust-generated WebAssembly that interops with JavaScript. Skip it when your Wasm target is not JavaScript, for example a WASI binary or a server-side runtime with its own ABI, because the generated glue is wasm-bindgen shaped.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 48 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap wasm-pack fills between cargo and npm
A Rust crate compiled to WebAssembly is not a JavaScript package. It is a .wasm binary with no metadata, no module wrapper, no type declarations and no package.json. Getting from one to the other by hand means invoking cargo with the right wasm target, running wasm-bindgen to generate the JS glue and the .d.ts files, running wasm-opt to shrink the binary, then writing the package manifest yourself, then remembering to do all of it again after every source change.
wasm-pack exists to collapse that chain. The README describes it as a one-stop shop for building and working with rust-generated WebAssembly that you would like to interop with JavaScript, in the browser or with Node.js. The audience is narrow and clear: Rust developers whose output is consumed by JavaScript, either published to the npm registry or dropped into an existing bundler workflow such as webpack. If nobody on the other side is writing import statements, the tool is aimed at a different project than yours.
What wasm-pack build actually orchestrates
The command list in the README maps to four jobs. new generates a project from a template. build produces an npm wasm package from a rustwasm crate. test runs browser tests. pack and publish create a tarball of the package or push it to a registry.
The interesting one is build, because it is a pipeline rather than a compiler invocation. The crate is compiled, wasm-bindgen generates the JavaScript bindings and type definitions that make Rust functions callable from JS, and the result is arranged into a directory with a manifest so npm and bundlers treat it as an ordinary dependency. The dependency list in Cargo.toml supports that reading: cargo_metadata is there to read the crate's own manifest, toml parses configuration, serde_json handles the generated manifest, and binary-install is how the tool fetches the external binaries it drives. wasm-pack itself is not the compiler or the binding generator; it is the coordinator that installs and invokes them.
That design has a practical consequence. The version of wasm-bindgen that gets used is a moving part, not a constant, and a mismatch between the bindgen version a crate expects and the one wasm-pack resolves is a class of failure the tool has to manage. It also means the output shape is wasm-bindgen's output shape: ES module glue, a .wasm payload, and generated TypeScript declarations. You are adopting that interface, not just a build command.
Installing wasm-pack and running a first build
The README points at an installer page in the project book rather than printing install commands inline, so the exact per-platform steps live at https://wasm-bindgen.github.io/wasm-pack/installer. The stated prerequisite is Rust 1.30.0 or later, with a development environment set up as described in the book's prerequisites section. If you already have a Rust toolchain, the crate is published on crates.io, which is the install route most Rust developers will reach for first:
cargo install wasm-packOnce the binary is on your PATH, the workflow starts from a crate. The README's quickstart lives in the book, and the command that does the work is build. Run it at the root of a crate that uses wasm-bindgen:
wasm-pack buildWhat you should see is a generated package directory containing the WebAssembly binary, the JavaScript glue, the type declarations and a package.json, which is the artifact the README describes as an npm wasm pkg. From there the package can be published to a registry with the publish command, or consumed locally by a bundler.
Logging is configured through the RUST_LOG environment variable, because the tool uses env_logger. The README gives this exact example:
RUST_LOG=info wasm-pack buildThat is worth knowing before your first confusing failure. A default run tells you relatively little about which stage went wrong; setting the log level is the difference between a generic error and knowing whether the failure was in compilation, binding generation or packaging.
Where wasm-pack stops being the right tool
The generated artifact is a JavaScript package. That is the whole point and also the boundary. If your WebAssembly module is meant to be loaded by a non-JavaScript host, through WASI or by a runtime that expects a raw module with its own ABI, the glue that wasm-pack produces is overhead you will have to strip or ignore. The README does not present a raw-module mode; every command it lists is framed around the npm package as the unit of output.
The browser test command is the second constraint. It runs browser tests, which means a browser is part of your test environment. Teams whose CI runs headless and minimal will need to make that work, and the README does not describe the harness it uses or how to configure it, so the book is the place to check before assuming it fits an existing pipeline.
Third, the tool is a coordinator, which means it inherits the failure modes of the things it coordinates. A toolchain version mismatch, a missing external binary, or a crate that does not use wasm-bindgen at all will surface as a wasm-pack error rather than a clear error from the underlying component. That is a reasonable trade for the convenience, but it is a real cost when you are debugging at speed.
Finally, the repository layout shows a wasm-pack-template directory and a template behind the new command. Templates are a starting point, not a constraint, but they do encode assumptions about crate structure that a hand-rolled project may not share.
wasm-pack versus trunk, and versus using wasm-bindgen directly
The honest alternative for a browser application is trunk, which takes a different position on the same problem. wasm-pack's unit of work is the package: it produces an npm-consumable artifact that a bundler or a registry then handles, and the README frames the output as something you use alongside JavaScript packages in workflows like webpack. trunk's unit of work is the application: it serves and bundles a web app from Rust sources, closer to a dev server than to a package publisher. If you are shipping a library that other JavaScript projects import, wasm-pack matches that shape. If you are shipping a page, the package step is a detour.
The other alternative is not a tool at all: run cargo, wasm-bindgen and wasm-opt yourself, or drive wasm-bindgen through its own CLI. That gives you exact control over the bindgen version, the optimization flags and the manifest contents, at the cost of writing and maintaining the orchestration. wasm-pack's value is precisely that orchestration, and the Cargo.toml dependency list shows how much of it there is: metadata reading, TOML and JSON handling, binary installation, directory walking. Reproducing that is a project, not a script.
A middle path exists for people who want the package without the browser test runner or the template assumptions: use wasm-pack build and ignore the rest of the command surface. The README lists the commands as separate capabilities, so nothing forces you to adopt new, test and publish together.
Release cadence, licence and what upgrading costs
The repository is not archived, and the last push was on 2026-08-12. Releases are not on a fixed clock: v0.13.1 landed on 2024-10-29, v0.14.0 on 2026-01-20, and v0.15.0 on 2026-05-15. That is a long gap followed by two releases in one year, which matters if you are pinning a version in CI and expecting a predictable upgrade window. The project is still pre-1.0, so minor version bumps are where behaviour changes land.
Licensing is dual: the Cargo.toml declares MIT OR Apache-2.0, and the repository carries both LICENSE-MIT and LICENSE-APACHE. That is the standard permissive Rust arrangement, and it is the same choice most of the ecosystem makes, so it rarely blocks adoption. One thing to check on your own side: the generated package and the binaries wasm-pack installs are separate artifacts with their own terms, and the README does not enumerate them. Reviewing what ends up in your published package is your job, not the tool's.
Upgrade cost concentrates in two places. The bindgen version the tool resolves can change between releases, which can change generated bindings. And the CLI surface can move, as the jump from 0.13 to 0.15 suggests. Pinning wasm-pack in CI and reading CHANGELOG.md before bumping is the cheap insurance, and both files are in the repository root.
Editorial conclusion
Adopt wasm-pack when your output is a JavaScript-consumable npm package and you want cargo, wasm-bindgen and packaging handled in one command; the README's own framing is a one-stop shop for Rust-generated WebAssembly that interops with JavaScript. Skip it when your Wasm target is not JavaScript, for example a WASI binary or a server-side runtime with its own ABI, because the generated glue is wasm-bindgen shaped. Before committing, check the docs installer page for the current install path on your platform, run wasm-pack build once on a real crate to confirm the generated package.json and type definitions match what your bundler expects, and confirm the Rust 1.30.0 minimum holds for your toolchain.
Frequently asked questions
How do I install wasm-pack?
The README points to an installer page at https://wasm-bindgen.github.io/wasm-pack/installer and lists Rust 1.30.0 or later as a prerequisite. The crate is published on crates.io, so cargo install wasm-pack is the route most Rust developers use.
What is wasm-pack?
It is a command line tool that builds rust-generated WebAssembly into npm packages that interop with JavaScript in the browser or with Node.js. Its commands cover generating a project, building a package, running browser tests, and packing or publishing to a registry.
What are the alternatives to wasm-pack?
Two realistic options are running cargo, wasm-bindgen and wasm-opt yourself for full control over versions and flags, or using a tool like trunk that bundles and serves a Rust web application instead of producing an npm package. The difference is the unit of work: package versus application.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/wasm-bindgen-wasm-pack)