# trunk-rs/trunk: a WASM bundler for Rust front ends

> Trunk turns a single index.html plus a Cargo.toml into a bundled WASM web app, with a dev server and change detection. It is aimed at Rust developers who want to ship to the browser without hand-writing a JavaScript build pipeline.

**trunk-rs/trunk** — Build, bundle & ship your Rust WASM application to the web.

- Repository: https://github.com/trunk-rs/trunk
- Website: https://trunk-rs.github.io/trunk/
- Stars: 4,396 · Forks: 323
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/trunk-rs-trunk

## What Trunk replaces for a Rust browser target

A Rust crate compiled to WebAssembly is not a web page. You get a .wasm module and, if you use wasm-bindgen, a JavaScript glue file. Something still has to copy those into an output directory, rewrite the paths in your HTML, and serve the result with the right MIME types. Trunk takes that job. The README describes it as a WASM web application bundler for Rust that uses "a simple, optional-config pattern for building & bundling WASM, JS snippets & other assets (images, css, scss) via a source HTML file." The audience is narrow and clear: developers whose front end is a Rust crate targeting the browser, typically through a framework such as Yew, Leptos or Seed, all three of which appear as directories under examples/. It is not a general-purpose JavaScript bundler and it does not try to be one.

## The source HTML file is the entry point

The design choice that separates Trunk from a Cargo subcommand wrapper is that the HTML file is the manifest. Instead of a separate build script listing inputs and outputs, you write an index.html and annotate the links and scripts Trunk should process. The README calls this a source HTML file. Trunk reads it, resolves the referenced Rust entry point, invokes the WASM build, and emits a dist directory with rewritten references.

The dependency list in Cargo.toml shows how the pieces are implemented rather than described. lol_html appears alongside htmlescape, which points at streaming HTML rewriting. minify-html and oxipng handle output compression of markup and images. notify and notify-debouncer-full are the file watchers behind change detection. axum and axum-server back the dev server, with the ws feature enabled for the reload channel. That is a coherent single-binary pipeline: watch, rebuild, rewrite, serve, reload.

The practical consequence is that asset handling is declarative. The README links a dedicated Assets page in the guide, and the examples directory includes yew-tailwindcss for CSS tooling and node-module for JavaScript dependencies. If your asset pipeline is unusual, the source HTML is where you express it, and the guide is where the syntax lives.

## Installing Trunk and running a first build

The README lists six install routes and points at the project website for the rest. The two that avoid compiling from source are a released binary from GitHub and cargo-binstall. If you already have a Rust toolchain and want a reproducible install from crates.io, the README gives this command:

```bash
cargo install trunk --locked
```

The --locked flag matters here: it tells Cargo to use the committed dependency versions in the crate's lockfile rather than resolving fresh ones, which is the difference between a build that matches what the maintainers tested and one that picks up whatever was published this week.

Once the binary is on your PATH, the workflow is a dev server against your app directory. The README links an App Setup page rather than inlining the steps, so the shape below follows that entry point: an index.html at the root of your crate, and trunk serve from the same directory.

```bash
trunk serve
```

You should see Trunk compile the crate, write the bundle, and start a server on a local port, with the browser opening to the app. Editing a Rust source file triggers a rebuild and a reload without you restarting anything, which is what the notify dependencies in Cargo.toml are for. For a production bundle, the README's CLI Commands page documents the build command; the configuration page covers Trunk.toml, and the repository ships a Trunk.toml at its own root as a working example of that file.

## Configuration files, proxies and the reverse proxy case

Trunk.toml is optional. The README's phrase "optional-config pattern" is accurate: a project with one HTML file and one crate needs no config at all. The config file becomes relevant when the dev server has to talk to a backend, which is where the proxy support in the README's feature list comes in. Trunk advertises both HTTP and WebSocket proxies, and examples/proxy and examples/behind-reverse-proxy exist in the repository, which tells you the maintainers treat fronting a separate API as a first-class scenario rather than an afterthought.

The trade-off is that configuration is where the documentation surface spreads out. The guide is split into separate pages for Assets, Configuration and CLI Commands, and the repository keeps a schemas/ directory alongside them. If you are debugging why an asset was not copied or why a path was rewritten the way it was, the answer is usually in one of those pages rather than in the README, which deliberately stays short and links outward.

## Where Trunk is the wrong tool

Trunk assumes Rust is the thing being compiled. If your application is a TypeScript or JavaScript front end that happens to call into a WASM module, Trunk's model inverts your build: you would be writing an HTML entry point for a Rust crate that is not the centre of your app. Use the bundler your front end already has and load the WASM module as an asset.

The second limitation is release maturity. The three most recent releases listed are all 0.22.0 beta builds, the newest from 2026-09-09, and the Cargo.toml in the repository declares version 0.22.0-rc.1. A team that needs a long-lived stable line should check what the current stable tag is before adopting, because the install commands in the README will pull whatever crates.io currently serves as latest unless you pin.

Third, the README does not document rollback or a downgrade path between Trunk versions. If a new release changes how your HTML is rewritten, the README is silent on how to reverse it; you would be relying on Cargo's own version pinning. Fourth, toolchain floor: Cargo.toml sets rust-version to 1.96.1, so an older compiler will refuse the build rather than produce a subtly different one. Verify that number against your CI image before you plan the migration.

## How Trunk differs from wasm-pack

wasm-pack and Trunk overlap at the compile step and diverge immediately after it. wasm-pack is built around publishing a crate as an npm package: it runs wasm-bindgen, generates JavaScript bindings, and produces output intended to be consumed by a JavaScript project's package manager. Trunk is built around serving a web application: it starts from HTML, owns the dev server, watches files, and emits a dist directory you deploy as static files.

That difference shows up in what each tool makes easy. If your deliverable is a library other JavaScript developers will import, wasm-pack's npm-shaped output is the right target and Trunk's HTML entry point is overhead. If your deliverable is a site, Trunk's dev server and reload loop remove a layer that wasm-pack leaves to you. The repository's examples/no-rust directory is a useful signal here: Trunk can bundle assets without compiling Rust at all, which is not a mode wasm-pack has any reason to support.

## Maintenance, licensing and upgrade cost

The repository is not archived, and the last push was on 2026-09-21, two days before this writing, with a 0.22.0 beta published on 2026-09-09. Development is ongoing and recent.

Licensing is dual: Cargo.toml declares "MIT/Apache-2.0" and the README states trunk is licensed under the terms of the MIT License or the Apache License 2.0, at your choosing. The repository carries LICENSE-MIT and LICENSE-APACHE at the root. For most teams this is the permissive combination they already accept; if your organisation has a policy against one of the two, the choice is yours to make, and this is not legal advice.

Upgrade cost is dominated by the beta cadence. Between 0.22.0-beta.1 in March 2026, beta.2 in July and beta.5 in September, the version string moved four times in six months. If you pin with cargo install trunk --locked or a fixed binary from the releases page, upgrades are deliberate and reviewable. If you track latest, you are testing beta behaviour in production. There is no documented migration guide in the README for moving between these versions, so budget time to diff the Configuration and CLI Commands pages when you bump.

## Conclusion

Adopt Trunk if your front end is a Rust crate compiled to wasm32-unknown-unknown and you want the HTML, WASM, JS snippets and static assets assembled by one binary instead of a Node toolchain. Skip it if you need a mature, stable release line: the newest published versions are 0.22.0 beta builds, and the repository's own Cargo.toml carries 0.22.0-rc.1, while the install paths in the README point at released binaries and crates.io. Before committing, pin a version, confirm that Cargo.toml requires rust-version 1.96.1 against your toolchain, and check the guide page for configuration and CLI commands for the specific keys you need.

## FAQ

### How do I install Trunk?

The README lists several routes: download a released binary from the GitHub releases page, run cargo binstall trunk for a pre-compiled binary, run cargo install trunk --locked to compile from crates.io, install from git or a local path, use brew install trunk, or use nix-shell -p trunk.

### What Rust version does Trunk require?

The repository's Cargo.toml sets rust-version to 1.96.1. A toolchain older than that will refuse to build the crate.

### What licence is Trunk released under?

The README states trunk is licensed under the MIT License or the Apache License 2.0, at your choosing, and Cargo.toml declares MIT/Apache-2.0. The repository contains LICENSE-MIT and LICENSE-APACHE files.

### Does Trunk work without any configuration file?

Yes. The README describes an optional-config pattern, and the guide keeps a separate Configuration page for Trunk.toml. The repository ships a Trunk.toml at its own root as an example of the file when you do need one.

### Can Trunk proxy requests to a backend API during development?

The README lists support for HTTP and WebSocket proxies as a dev server feature, and the repository includes examples/proxy and examples/behind-reverse-proxy directories covering that setup.

## Sources

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

---

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