Cargo2nix
Granular builds of Rust projects for Nix
Install / Use
/learn @cargo2nix/Cargo2nixREADME
cargo2nix
Bring Nix dependency management to your Rust project!
- Development Shell - knowing all the dependencies means easy creation of
complete shells. Run
nix developordirenv allowin this repo and see! - Caching - CI & CD pipelines move faster when purity guarantees allow skipping more work!
- Reproducibility - Pure builds. Access to all of nixpkgs for repeatable environment setup across multiple distributions and platforms
Run it now!
With nix (with flake support) installed, generate a
Cargo.nix for your project:
# Use nix to get cargo2nix & rust toolchain on your path
nix develop github:cargo2nix/cargo2nix#bootstrap
# In directory with Cargo.toml & Cargo.lock files (cargo generate-lockfile)
cargo2nix
# Or skip the shell and run it directly
nix run github:cargo2nix/cargo2nix
# You'll need this in version control
git add Cargo.nix
Use what you generated!
To consume your new Cargo.nix, write a nix expression like that found in the
hello world example.
A bare minimum flake.nix:
{
inputs = {
cargo2nix.url = "github:cargo2nix/cargo2nix/release-0.12";
flake-utils.follows = "cargo2nix/flake-utils";
nixpkgs.follows = "cargo2nix/nixpkgs";
};
outputs = inputs: with inputs;
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [cargo2nix.overlays.default];
};
rustPkgs = pkgs.rustBuilder.makePackageSet {
rustVersion = "1.75.0";
packageFun = import ./Cargo.nix;
};
in rec {
packages = {
# replace hello-world with your package name
hello-world = (rustPkgs.workspace.hello-world {});
default = packages.hello-world;
};
}
);
}
For a more complete project with CI & CD mostly ready to go, check out Unixsocks or cargo2nix's own CI workflow.
Build with nix
# these must be in version control!
git add flake.nix Cargo.nix
nix build
...
...
...
./result-bin/bin/hello
hello world!
Check out our series of example projects which showcase how to use
cargo2nix in more detail.
Development environment
In this repo, simply use nix develop or direnv allow. Even if you are on
a bare NixOS system or fresh OSX environment with no dependencies or toolchains
installed, you will have everything you need to run cargo build. See the
devShell attribute in flake.nix to see how to prepare this kind of shell.
The workspaceShell function, created by makePackagSet, accepts
all the same options as the nix mkShell function.
Maintaining your project
In your flake, you can choose your cargo2nix version by changing the URL.
| Flake URL | Result | |-----------------------------------------|:----------------------------------------------------------:| | github:cargo2nix/cargo2nix/ | latest release (check repo's default branch, release-0.12) | | github:cargo2nix/cargo2nix/release-0.12 | use a specific release | | github:cargo2nix/cargo2nix/main | latest features & fixes |
Only use unstable for developing with the latest features. PR's against old releases can be accepted but no active support will be done. The default branch for this repo is updated whenever a new release tag is made. Only specific release branches are "stable."
Update your flake lock with the latest or a specific version of cargo2nix:
nix flake lock --update-input cargo2nix
nix flake lock --update-input cargo2nix --override-input cargo2nix github:cargo2nix/cargo2nix/?rev=d45481420482fa7d9b0a62836555e24ec07d93be
If you need newer versions of Rust or the flake-utils inputs, just specify them using URL instead of follows.
Arguments to makePackageSet
The makePackageSet function from the
overlay accepts arguments that
adjust how the workspace is built. Only the packageFun argument is required.
Cargo2nix's own flake.nix has more information.
-
rustVersion- is either a version string or YYYY-MM-DD date-string -
rustChannel-"nightly""beta""stable" -
rustProfile-"default"or"minimal"usually -
extraRustComponents-["clippy" "miri"]etc -
workspaceSrc- override where the source is supplied relative to the Cargo.nix -
rootFeatures- a list offoo/featurestrings for workspace crate features -
packageOverrides- control over the individual crate overrides used to make them compatible on some platforms, for example to tweak C lib consumption -
target- setting an explicit target, useful when cross compiling to obtain a specific Rust target that doesn't align with the nixpkgs target
Contents of Package Set
rustPkgs contains all crates in the dependency graph and some extra
conveniences for development. The workspace crates are also exposed via a
workspace attribute.
rustPkgs.<registry>.<crate>.<version> is an example of a crate function
path. Calling the function results in a completed derivation, which can be used
as a flake output. They support all the normal behaviors such as override and
overrideAttrs. See mkCrate.nix for the full set of
arguments the crate function supports.
rustPkgs.workspace.<crate> are usually the packages you will use. The other
paths look like:
rustPkgs."registry+https://github.com/rust-lang/crates.io-index".openssl."0.10.30"
rustPkgs.workspaceShell is a derivation using Nix's standard mkShell,
embellished with information we learned from the dependencies and their
overrides, enabling vanilla cargo build to work in a nix develop shell.
Overrides
This is for finished derivations, not for dependencies. Keep reading below for
using makeOverride in the dependency tree.
workspaceShell and crates both support override and
overrideAttrs like normal Nix derivations. This allows you to customize
the workspace shell or a build step in your workspace crate very easily. See
nix show-derivation and nix show-derivation #devShell for more information.
More Control
You can make overrides to packages in the dependency tree. See examples in
overrides.nix. Overriding the buildPhase etc is
possible for a single crate without modifying mkcrate.nix in cargo2nix
directly. The output of nix show-derivation can be valuable when determining
what the current output result is.
The most important function in cargo2nix source is mkcrate.nix because it's how we store information in dependents and replay them back when building dependents. It is vital for building crates in isolation.
Newer Rust versions
In order to use the latest Rust versions you may need to include rust-overlay directly in your flake like so:
{
inputs = {
rust-overlay.url = "github:oxalica/rust-overlay/stable";
cargo2nix = {
url = "github:cargo2nix/cargo2nix/release-0.12";
inputs.rust-overlay.follows = "rust-overlay";
};
};
}
To use a Rust version that was released after you added the rust-overlay input
you will need to run nix flake update rust-overlay to get the latest
rust-overlay version.
How it works
-
The
cargo2nixutility reads the Rust workspace configuration andCargo.lockand generates nix expressions that encode some of the feature, platform, and target logic into aCargo.nix -
The cargo2nix Nixpkgs overlay consumes the
Cargo.nix, feeding it what you pass tomakePackageSetto provide workspace outputs you can expose in your nix flake -
Because we know all of the dependencies, it's easy to create a shell from those dependencies as environment setup using the
workspaceShellfunction and exposing the result in thedevShellflake output
Building crates isolated from each other
Just like regular cargo builds, the Nix dependencies form a [DAG][DAG], but
purity means we only expose essential information to dependencies and manually
invoke cargo. Communication from dependencies to dependents is handled by
writing some extra outputs and then reading those outputs inside the next
dependent build.
There's two broad categories of information that need to be transmitted when hand-building crates in isolation:
-
Global information
- target such as
x86_64-unknown-linux-gnu - cargo actions such as
buildortest - features which turn on optional dependencies & downstream features via logic
in the
Cargo.nixexpressions
This information is known before any of the crates are built. It's used at evaluation time to decide what will be built. See
nix show-derivationresults. - target such as
-
Propagated information
Each dependency writes information such as linker flag
Related Skills
himalaya
347.0kCLI to manage emails via IMAP/SMTP. Use `himalaya` to list, read, write, reply, forward, search, and organize emails from the terminal. Supports multiple accounts and message composition with MML (MIME Meta Language).
node-connect
347.0kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
taskflow
347.0kname: taskflow description: Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layer
frontend-design
107.8kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
