# cargo-leptos builds a Leptos app's server and wasm client from one Cargo.toml

> cargo-leptos is the build tool for the Leptos web framework, and it exists because a Leptos app is two compilation targets rather than one: a native server binary and a wasm client. The tool compiles both, runs them in parallel in watch mode, handles the SCSS and CSS pipeline, and drives wasm-bindgen and wasm-opt for you.

**leptos-rs/cargo-leptos** — Build tool for Leptos (Rust)

- Repository: https://github.com/leptos-rs/cargo-leptos
- Stars: 546 · Forks: 199
- Language: Rust
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/leptos-rs-cargo-leptos

## Why a Leptos project needs its own build tool at all

cargo-leptos is the build tool for Leptos, the Rust web framework, and the reason it exists is stated in the build features section of the README in two sentences.

When building with cargo-leptos, the frontend library package is compiled into wasm using target wasm-unknown-unknown and the features --no-default-features --features=hydrate. The server binary is compiled with the features --no-default-features --features=ssr.

That is the whole problem in two lines. A Leptos application is one program that has two halves: a Rust server that renders HTML, and a Rust client compiled to WebAssembly that hydrates that HTML in the browser. Those two halves need different feature flags, different targets and different compilation settings, and the feature flags are not optional decoration. The hydrate feature is what turns the client code into the interactive version, and the ssr feature is what turns the server code into the renderer. Getting either wrong produces an application that renders but does not hydrate, or one that does not render at all.

Doing that by hand means two cargo invocations with different flags, in the right order, plus wasm-bindgen, plus wasm-opt, plus a CSS pipeline, plus a watch loop that rebuilds only the half that changed. That is the work the tool takes over, and it is the reason a framework with an unusual compilation model needs a first-party build tool rather than a set of documented cargo aliases.

The tool is Rust, MIT licensed, at version 0.3.11 in the Cargo.toml, with a rust-version of 1.82.0 and edition 2021. The authors listed are Henrik Akesson, Greg Johnston and Ben Wishovich. The default branch is main, the last push was on 2026-10-16, and the recent releases are v0.3.11 from 2026-10-02, v0.3.10 from 2026-09-26 and v0.3.9 from 2026-09-18, which is a steady release cadence of roughly every two weeks. The package describes itself as a build tool for Leptos, categorised under development-tools, wasm and web-programming.

## Installing the tool and the dependency it downloads for you

The install is a single cargo invocation:

```bash
cargo install --locked cargo-leptos
```

The --locked flag matters here, because cargo-leptos pulls in a large dependency tree and a locked build gives you the versions the maintainers tested rather than whatever resolves today.

There is a note that this may require additional dependencies for SSL on some systems, and a specific failure case: if the installation fails while building openssl-sys, you will need to install additional tools before retrying the build. That is the openssl-sys crate failing to find a system OpenSSL, which is a common enough problem on Linux distributions that ship OpenSSL 3 that the README calls it out.

For the bleeding-edge version, the README gives a second form that installs from git rather than from crates.io:

```bash
cargo install --git https://github.com/leptos-rs/cargo-leptos --locked cargo-leptos
```

And the help is a subcommand:

```bash
cargo leptos --help
```

The dependency that the tool manages for you is sass. The dependency for sass is automatically installed in a cache directory when it is used, if it is not already installed and found by which. Different versions of the dependencies might accumulate in that directory, so the README says you can delete it.

The cache location follows the platform convention:

| OS      | Example                                   |
| ------- | ----------------------------------------- |
| Linux   | /home/alice/.cache/cargo-leptos           |
| macOS   | /Users/Alice/Library/Caches/cargo-leptos  |
| Windows | C:\Users\Alice\AppData\Local\cargo-leptos |

If you wish to make it mandatory to install your dependencies, or are using Nix or NixOs, you can install it with the no_downloads feature enabled to prevent cargo-leptos from trying to download and install them:

```bash
cargo install --features no_downloads --locked cargo-leptos
```

That last point is the one to notice if you build in CI or on Nix, where a network fetch during a build is unwelcome. The repository has a flake.nix and a flake.lock at the root, so Nix users are a first-class case rather than an afterthought.

For new projects, the new command creates a project from a template using cargo-generate, and the templates listed include an Actix starter, an Axum starter, and an Axum starter keeping client and server code in separate crates in a workspace.

## The feature list, and what watch mode actually does

The feature list is what tells you what the tool is for, and two entries stand out.

The first is parallel build of server and client in watch mode for fast developer feedback. Since the two halves are separate compilation targets with different feature flags, a naive watch loop would rebuild both on every save. The tool builds them in parallel and rebuilds only what changed.

The second is CSS hot-reload, described as no page-reload, only CSS updated. In a Rust web framework the CSS is compiled by the tool rather than by the framework, so the tool has to take over the browser reload behaviour itself, and the distinction between reloading the stylesheet and reloading the page is what keeps the fast feedback loop intact. A page reload would throw away the state of the running Rust server and the client-side state, which in a Leptos app means losing whatever the user was doing.

The rest of the list is the pipeline. SCSS compilation using dart-sass, and CSS transformation and minification using Lightning CSS. The server and client wasm binaries are built using Cargo. JS and wasm bindings are generated with wasm-bindgen, including support for JS Snippets for when you want to call some JS code from your wasm. The wasm is then optimised with wasm-opt from Binaryen.

There are four commands to remember. The watch command is for automatic rebuilds with browser live-reload. The test command runs tests of the lib and bin packages that make up the Leptos project. The build command builds the server and client. And the end-to-end command is for building, running the server and calling a bash shell hook, which would typically launch Playwright or similar.

That last one is the piece that makes end-to-end testing possible in a two-target application. The hard part of testing a server-plus-client app is that you need both running and coordinated, and the tool's answer is to build and start the server and then hand control to a script.

One limitation is stated plainly in the feature list: build server and client for hydration, and client-side rendering mode not supported. A Leptos application is a server-rendered application with an interactive client, and this tool builds that shape only.

## Configuration lives in Cargo.toml, and the workspace form is the one to read

The configuration is not a separate file. It goes in the Cargo.toml, which is the design decision that makes cargo-leptos feel like part of Cargo rather than a wrapper around it.

In a single-package setup, the code for both the frontend and the server is in one package, and the configuration parameters are defined in the Cargo.toml section [package.metadata.leptos]. All paths are relative to the package root, that is, to the Cargo.toml file.

In a workspace setup, both single-package and multi-package projects are supported, the latter being when the frontend and the server reside in different packages. All workspace members whose Cargo.toml define the [package.metadata.leptos] section are automatically included as Leptos single-package projects. The multi-package projects are defined on the workspace level in the Cargo.toml's section [[workspace.metadata.leptos]], which takes three mandatory parameters:

```toml
[[workspace.metadata.leptos]]
# project name
name = "leptos-project"
bin-package = "server"
lib-package = "front"

# more configuration parameters...
```

The double square brackets are the point, and the README explains it: several projects can be defined and one package can be used in several projects. So a workspace can hold several Leptos applications, each with its own server and client, sharing packages.

The three mandatory parameters are name, bin-package and lib-package, and they map onto the two-target compilation model. bin-package names the package that produces the server binary, compiled with the ssr feature. lib-package names the package that produces the client library, compiled to wasm with the hydrate feature. Getting these wrong means the tool builds the wrong things, and it is worth reading the examples in the repository, which include examples/project/, examples/workspace/ and examples/css-bundle/, before writing the metadata from scratch.

The README also flags a subtlety that trips people up: these parameters are used either in the workspace section or in the package section, and the Cargo manifest uses the word target with two different meanings, as a package's configured [[bin]] targets and as the compiled output. That ambiguity in Cargo's own vocabulary is why the parameters list is long.

## Where cargo-leptos is the wrong tool

Three limits, and the first is about what it assumes about your project.

The first is that it is Leptos specific and only Leptos specific. The metadata sections it reads are named for Leptos, the feature flags it passes are hydrate and ssr which are Leptos feature flags, and the whole build model assumes the server-rendered plus hydrated shape. There is no configuration that makes it build a pure client-side application, and the README says so. If you are using another Rust web framework, or if you want pure CSR, this is the wrong tool and the effort of adapting it would exceed writing the build steps.

The second is the dependency on external toolchain binaries. The tool downloads and installs sass itself, and it expects to find tools on the system through which. wasm-bindgen and wasm-opt are part of the pipeline, and lightningcss is compiled in rather than invoked. That works well on a developer machine with network access and becomes a problem in a hermetic build: the no_downloads feature exists precisely because the automatic download is the wrong behaviour in a Nix or CI environment, and enabling it means you own the sass installation.

The third is the version pinning of a fast-moving framework. cargo-leptos at 0.3.11 depends on leptos_hot_reload at 0.8.6, on swc at 79.0, on lightningcss at a 1.0.0-alpha version, and on axum at 0.8.9 with the ws feature. Some of those pins are close to the bleeding edge, which is what keeps the tool current, and it also means a Leptos upgrade can pull a cargo-leptos upgrade with it, and the README ships an UPGRADE.md at the repository root for exactly that.

The alternative approach is to run cargo twice by hand, once with the hydrate feature and the wasm32 target and once with the ssr feature for the server, and then add wasm-bindgen and wasm-opt to the pipeline. The difference in approach is that cargo-leptos gives you one command, one configuration surface in Cargo.toml, a watch loop that rebuilds only the changed half, and a CSS pipeline you do not have to assemble, at the cost of a tool you have to keep in step with the framework version. For a team already building with Leptos, the manual route means maintaining a set of shell scripts that the tool does for free, and for a team not using Leptos, the tool is simply the wrong shape.

## Conclusion

Adopt cargo-leptos if you are building a Leptos application, because the alternative is hand-rolling the two-target build, the CSS pipeline and the wasm tooling, and the tool handles the feature flags that distinguish the hydration build from the server build. Do not adopt it if you are not using Leptos, since the metadata sections it reads are Leptos specific. Verify first that your Rust toolchain satisfies the 1.82.0 minimum in the Cargo.toml and that the rust-toolchain.toml file matches what you expect, that the sass dependency can be fetched or that you install it yourself with the no_downloads feature, that the lightningcss version you resolve is compatible with your browserslist targets, and that the workspace metadata you write names the right bin-package and lib-package, since a mismatch there produces a server that serves a client that was never built.

## FAQ

### How do I install cargo-leptos?

Run cargo install --locked cargo-leptos, or cargo install --git https://github.com/leptos-rs/cargo-leptos --locked cargo-leptos for the newest source build. If the build fails while building openssl-sys, you will need to install additional tools before retrying, according to the README.

### What does cargo-leptos actually compile for a Leptos app?

Two targets. The frontend library package is compiled to wasm using the wasm-unknown-unknown target with --no-default-features --features=hydrate, and the server binary is compiled with --no-default-features --features=ssr. The tool also runs wasm-bindgen for the bindings and wasm-opt for the optimisation.

### Where do I configure cargo-leptos?

In Cargo.toml. A single-package project uses the [package.metadata.leptos] section, and a multi-package workspace project uses the [[workspace.metadata.leptos]] section, whose mandatory parameters are name, bin-package and lib-package. All paths are relative to the package root.

### What is the no_downloads feature for?

It prevents cargo-leptos from downloading and installing its optional dependencies, such as sass, so you can manage them yourself. The README recommends it if you want the dependencies to be mandatory, or if you are using Nix or NixOS, and you install with cargo install --features no_downloads --locked cargo-leptos.

### How do I run end-to-end tests on a Leptos app with cargo-leptos?

The end-to-end command builds the project, runs the server and calls a bash shell hook, which would typically launch Playwright or similar. There is also a separate test command for running the tests of the lib and bin packages that make up the Leptos project.

### Does cargo-leptos support client-side rendering?

No. The feature list states that it builds the server and client for hydration and that client-side rendering mode is not supported. A Leptos application built with it is a server-rendered app with a hydrated client.

## Sources

- [Issues](https://github.com/leptos-rs/cargo-leptos/issues)
- [leptos-rs/cargo-leptos on GitHub](https://github.com/leptos-rs/cargo-leptos)
- [License: MIT](https://github.com/leptos-rs/cargo-leptos/blob/main/LICENSE)
- [README](https://github.com/leptos-rs/cargo-leptos/blob/main/README.md)
- [Releases](https://github.com/leptos-rs/cargo-leptos/releases)

---

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