anthropics/cargo-nix-plugin
Rust
Captured source
source ↗anthropics/cargo-nix-plugin
Description: A Nix plugin that resolves Cargo workspaces natively and allows for crate level builds
Language: Rust
License: Apache-2.0
Stars: 28
Forks: 9
Open issues: 6
Created: 2026-05-19T17:07:44Z
Pushed: 2026-05-30T18:47:01Z
Default branch: main
Fork: no
Archived: no
README:
cargo-nix-plugin
A Nix plugin that resolves Cargo workspaces natively, replacing the generated Cargo.nix file from crate2nix with a single builtins.resolveCargoWorkspace primop.
What It Does
- Resolves Cargo workspaces at native speed — directly from
Cargo.lockand
the sparse registry index, no cargo binary required (or, optionally, from pre-generated cargo metadata JSON)
- Pre-evaluates
cfg()target expressions for the requested platform - Returns a Nix attrset compatible with
buildRustCrate - Eliminates the
crate2nix generatestep and the 50K-100K lineCargo.nix
Install
Add the plugin to your Nix configuration:
# nix.conf or via --option — point at the directory so the right # extension (.so/.dylib) is picked up automatically plugin-files = /path/to/cargo-nix-plugin/lib/nix/plugins
Or use the flake output:
{
inputs.cargo-nix-plugin.url = "github:anthropics/cargo-nix-plugin";
}Usage
Default (lockfile resolve)
Just point at your workspace root:
cargoNix = cargo-nix-plugin.lib {
inherit pkgs;
src = ./.; # must contain Cargo.toml + Cargo.lock
};The plugin reads Cargo.lock plus the sparse registry index directly — no cargo binary, no crate sources at eval time. On first use it fetches each crate's index entry (a few hundred bytes) into $CARGO_HOME and reuses it thereafter.
If your environment already redirects cargo to a mirror, the resolver follows the same configuration — CARGO_REGISTRIES_CRATES_IO_INDEX or [source.crates-io] replace-with in .cargo/config.toml — so no plugin-specific setup is required:
# .cargo/config.toml — honoured by both cargo and the plugin [source.crates-io] replace-with = "mirror" [source.mirror] registry = "sparse+https://artifactory.example/api/cargo/crates/index/"
If every index lookup fails (e.g. egress to index.crates.io is blocked and no mirror is configured), evaluation fails loudly rather than silently producing derivations with missing features.
Explicit metadata
Alternatively, pre-generate cargo's resolution and pass it in:
cargo metadata --format-version 1 --locked > metadata.json
Then pass it explicitly:
cargoNix = cargo-nix-plugin.lib {
inherit pkgs;
metadata = builtins.readFile ./metadata.json;
cargoLock = builtins.readFile ./Cargo.lock;
src = ./.;
};A helper is also available:
nix run .#generate-metadata -- > metadata.json
Warming the index cache out of band
In the rare case where the evaluating host has *no* reachable index at all, cargo-nix-prefetch can populate $CARGO_HOME ahead of time on a connected host (it observes the same mirror precedence as the plugin):
nix run .#cargo-nix-prefetch -- --manifest-path ./Cargo.toml nix run .#cargo-nix-prefetch -- --manifest-path ./Cargo.toml --check # verify
Use --output DIR to write into a fresh directory instead of the ambient $CARGO_HOME, then point the resolver at it explicitly:
nix run .#cargo-nix-prefetch -- --manifest-path ./Cargo.toml --output ./.cargo-index
cargoNix = cargo-nix-plugin.lib {
inherit pkgs;
src = ./.;
cargoHome = ./.cargo-index; # pre-warmed by cargo-nix-prefetch
};The same shape works wrapped in a fixed-output derivation if you want the cache pinned by hash rather than checked in.
Git dependencies
git+… entries in Cargo.lock are fetched at eval time with builtins.fetchGit { url; rev; allRefs = true; submodules = true; } so the resolver can read each crate's Cargo.toml (the registry index has no record of them). Submodules are pulled to match cargo, which always recurses them for git deps. When the upstream repo is a Cargo workspace, the resolver locates the right member and passes its sub-directory to buildRustCrate as workspace_member.
Override gitSources when fetchGit can't reach the repo (private auth, vendored fixture), to pin a narHash/use a FOD fetcher, or to skip submodules for a repo that doesn't need them:
cargoNix = cargo-nix-plugin.lib {
inherit pkgs;
src = ./.;
gitSources = {
# key = "${url}#${rev}" with git+ and ?query stripped — exactly what
# appears in Cargo.lock after `git+` and before `?`, plus `#REV`.
"https://github.com/Byron/gitoxide#abcdef…" = pkgs.fetchgit {
url = "git@github.com:Byron/gitoxide";
rev = "abcdef…";
hash = "sha256-…";
};
};
};A git+ source without a pinned #rev is rejected; Cargo.lock always pins one.
Debug logging
The resolver stays quiet on the happy path so eval output isn't drowned in progress noise. Set CARGO_NIX_DEBUG=1 to surface the informational logs (mirror selection, index prefetch timings, per-crate retry attempts) on stderr. Warnings about misconfiguration and hard errors are always printed regardless of this flag.
Example
The plugin must be loaded by the same Nix version it was compiled against (see [Compatibility](#compatibility)). Evaluate with the plugin loaded via --option:
PLUGIN=$(nix build .#cargo-nix-plugin --print-out-paths)
NIX=$(nix build nixpkgs#nixVersions.nix_2_34 --print-out-paths | grep -v man)
$NIX/bin/nix-instantiate --eval \
--option plugin-files "$PLUGIN/lib/nix/plugins" \
-E '(import ./lib { pkgs = import {}; src = ./.; }).workspaceMembers'Or permanently in nix.conf / ~/.config/nix/nix.conf (only if your system Nix matches the plugin's build version):
plugin-files = /path/to/cargo-nix-plugin/lib/nix/plugins
flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
cargo-nix-plugin.url = "github:anthropics/cargo-nix-plugin";
};
outputs = { self, nixpkgs, cargo-nix-plugin }:
let
pkgs = import nixpkgs { system = "x86_64-linux"; };
cargoNix = cargo-nix-plugin.lib {
inherit pkgs;
src = ./.;
};
in {
packages.x86_64-linux.default = cargoNix.rootCrate.build;
};
}Clippy
The wrapper provides cached clippy checks via cargoNix.clippy. Dependencies are compiled once with rustc and cached in the Nix store; only workspace members are re-checked with clippy-driver. This means running clippy on a large workspace is as fast as compiling just your local…
Excerpt shown — open the source for the full document.
Notability
notability 2.0/10Routine repo with low stars, not a major release.