Crate2nix
crate2nix builds your cargo-based rust project crate-by-crate with nix
Install / Use
/learn @nix-community/Crate2nixREADME
crate2nix
crate2nix generates Nix build files for
Rust/Cargo projects,
building each crate individually for precise, incremental rebuilds.
- Incremental CI builds -- only rebuild the crates that actually changed.
- Full Nix integration -- remote builds, binary caches, Docker images, NixOS modules.
- Local dev unchanged -- keep using
cargoandrust-analyzeras usual.
Quick start
Without installing
nix run nixpkgs#crate2nix -- generate
nix build -f Cargo.nix rootCrate.build
With a flake template
nix flake init --template github:nix-community/crate2nix
Installing
# From nixpkgs
nix profile install nixpkgs#crate2nix
# Latest development version
nix profile install github:nix-community/crate2nix
Then, inside your project:
crate2nix generate # creates Cargo.nix
nix build -f Cargo.nix rootCrate.build
How it works
crate2nix reads Cargo.toml and Cargo.lock, resolves the full dependency
tree via cargo metadata, prefetches source hashes, and renders a Cargo.nix
file through Tera templates. The generated file contains one Nix derivation per
crate, so Nix rebuilds only what changed.
Two generation strategies are supported:
| Strategy | Pros | Cons |
| --- | --- | --- |
| Manual (crate2nix generate) | No IFD, full build parallelism | Must regenerate when deps change |
| Auto (Import From Derivation) | Always in sync with Cargo.lock | May reduce parallelism |
Nix API
tools.nix exposes helpers for use in your own Nix expressions:
let
crate2nix = builtins.fetchTarball "https://github.com/nix-community/crate2nix/tarball/master";
tools = import "${crate2nix}/tools.nix" { inherit pkgs; };
generated = tools.generatedCargoNix {
name = "my-project";
src = ./.;
};
project = pkgs.callPackage "${generated}/default.nix" {};
in
project.rootCrate.build
Or the shorthand appliedCargoNix which combines generation and import.
JSON output (experimental)
crate2nix generate --format json emits a pre-resolved JSON file instead of
Cargo.nix. All dependency resolution — feature expansion, cfg() platform
filtering, optional dep activation — happens in Rust, so the Nix side is a
trivial data consumer with no O(n×m) eval-time logic.
Generating
crate2nix generate --format json
This writes ./Cargo.json by default (use -o to override). The output is
compact: empty fields and already-resolved feature maps are omitted, so the
JSON is typically smaller than the equivalent Cargo.nix.
Consuming in Nix
Use lib/build-from-json.nix (shipped in this repo) to turn the JSON into
buildRustCrate derivations:
let
cargoNix = import ./lib/build-from-json.nix {
inherit pkgs;
src = ./.;
resolvedJson = ./Cargo.json;
};
in {
# Single crate
my-binary = cargoNix.workspaceMembers.my-crate.build;
# Root crate (if the workspace has one)
default = cargoNix.rootCrate.build;
# All workspace members linked together
all = cargoNix.allWorkspaceMembers;
}
The consumer accepts two optional arguments for customisation:
buildRustCrateForPkgs— override thebuildRustCrateused (e.g. for a custom toolchain)defaultCrateOverrides— per-crate build fixups, same as the existingCargo.nixworkflow
Documentation
Full documentation is at https://nix-community.github.io/crate2nix/, covering:
- Installation options
- Generation strategies
- Building binaries
- Feature selection
- Crate overrides
- Known restrictions
- Changelog
Contributing
Contributions are welcome! See the contributing guide for details.
License
Apache-2.0
