🚧 This project is under development and is not ready for production yet. APIs are subjects to change.
Build Rust crates with Nix Build System.
cargo dependency during building. Only rustc.[workspace]
membersmembersexcludes
FIXME: Buggy.resolver
Currently has custom resolution algorithm, more like v2.links[profile][{,dev-,build-}dependencies][features]
[target.<cfg>.dependencies][patch]
Automatically supported. Since the dependency graph Cargo.lock currently relies on cargo's generation.noc helper
noc init: Initial template flake.nix generation
registryregistry-indexgitpath inside workspacepath outside workspaceCargo.lock generation and updatingcachix and run cachix use nocargo (see more detail about cachix), orhttps://nocargo.cachix.org with public key nocargo.cachix.org-1:W6jkp5htZBA1tUdU8XHLaD7zBrIFnor0MsLhHgrJeHk=Cargo.lock already created by cargo.nix run github:oxalica/nocargo init to generate flake.nix. Or write it by hand by following the next section.nix flake show. Typically, the layout would be like,
└───packages
└───x86_64-linux
├───default: package 'rust_mypkg1-0.1.0' # The "default" package. For workspace, it's the top-level one if exists.
├───mypkg1: package 'rust_mypkg1-0.1.0' # Crate `mypkg1` with `release` profile.
├───mypkg1-dev: package 'rust_mypkg1-debug-0.1.0' # Crate `mypkg1` with `dev` profile.
├───mypkg2: package 'rust_mypkg2-0.1.0' # etc.
└───mypkg2-dev: package 'rust_mypkg2-debug-0.1.0'
nix build .#<pkgname> to build your package. Built binaries (if any) will be placed in ./result/bin, and the library will be in ./result/lib.flake.nix structure for referenceA template flake.nix with common setup are below. It's mostly the same as the generated one, except that the helper noc will scan the workspace and discover all external registries and git dependencies for you.
{
description = "My Rust packages";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
nocargo = {
url = "github:oxalica/nocargo";
inputs.nixpkgs.follows = "nixpkgs";
# See below.
# inputs.registry-crates-io.follows = "registry-crates-io";
};
# Optionally, you can explicitly import crates.io-index here.
# So you can `nix flake update` at any time to get cutting edge version of crates,
# instead of waiting `nocargo` to dump its dependency.
# Otherwise, you can simply omit this to use the locked registry from `nocargo`,
# which is updated periodically.
# registry-crates-io = { url = "github:rust-lang/crates.io-index"; flake = false; };
};
outputs = { nixpkgs, flake-utils, nocargo, ... }@inputs:
flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
let
# The entry API to make Nix derivations from your Rust workspace or package.
# The output of it consists of profile names, like `release` or `dev`, each of which is
# a attrset of all member package derivations keyed by their package names.
ws = nocargo.lib.${system}.mkRustPackageOrWorkspace {
# The root directory, which contains `Cargo.lock` and top-level `Cargo.toml`
# (the one containing `[workspace]` for workspace).
src = ./.;
# If you use registries other than crates.io, they should be imported in flake inputs,
# and specified here. Note that registry should be initialized via `mkIndex`,
# with an optional override.
extraRegistries = {
# "https://example-registry.org" = nocargo.lib.${system}.mkIndex inputs.example-registry {};
};
# If you use crates from git URLs, they should be imported in flake inputs,
# and specified here.
gitSrcs = {
# "https://github.com/some/repo" = inputs.example-git-source;
};
# If some crates in your dependency closure require packages from nixpkgs.
# You can override the argument for `stdenv.mkDerivation` to add them.
#
# Popular `-sys` crates overrides are maintained in `./crates-io-override/default.nix`
# to make them work out-of-box. PRs are welcome.
buildCrateOverrides = with nixpkgs.legacyPackages.${system}; {
# Use package id format `pkgname version (registry)` to reference a direct or transitive dependency.
"zstd-sys 2.0.1+zstd.1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = old: {
nativeBuildInputs = [ pkg-config ];
propagatedBuildInputs = [ zstd ];
};
# Use package name to reference local crates.
"mypkg1" = old: {
nativeBuildInputs = [ git ];
};
};
# We use the rustc from nixpkgs by default.
# But you can override it, for example, with a nightly version from https://github.com/oxalica/rust-overlay
# rustc = rust-overlay.packages.${system}.rust-nightly_2022-07-01;
};
in rec {
# For convenience, we hoist derivations of `release` and `dev` profile for easy access,
# with `dev` packages postfixed by `-dev`.
# You can export different packages of your choice.
packages = ws.release
// nixpkgs.lib.mapAttrs' (name: value: { name = "${name}-dev"; inherit value; }) ws.dev
// {
# The "default" features are turned on by default.
# You can `override` the library derivation to enable a different set of features.
# Explicit overriding will disable "default", unless you manually include it.
mypkg1-with-custom-features = (ws.release.mypkg1.override {
# Enables two features (and transitive ones), and disables "default".
features = [ "feature1" "feature2" ];
}).bin;
};
});
}
Main differences are already clarified on the top.
nocargo is inspired by cargo2nix and buildRustCrate in nixpkgs. We are more like cargo2nix while the generation part is implemented by pure Nix, but less like naersk which is a wrapper to call cargo to build the package inside derivations.
In other words, we and cargo2nix use Nix as a Build System, while nearsk use Nix as a Package Manager or Packager.
| nocargo | cargo2nix/buildRustCrate | naersk | buildRustPackage | |
|---|---|---|---|---|
Depend on cargo | Updating Cargo.lock | Updating & generating & building | Updating & vendoring & building | Building |
| Derivation granularity | Per crate | Per crate | Per package + one dependency closure | All in one |
| Crate level sharing | ✔️ | ✔️ | ✖ | ✖ |
| Binary substitution per crate | ✔️ | Not implemented | ✖ | ✖ |
| Code generation | ✖ | ✔️ | ✖ | ✖ |
| Edit workspace & rebuild | Rebuild leaf crates | Rebuild leaf crates | Rebuild leaf crates | Refetch and rebuild all crates |
| Edit dependencies & rebuild | Rebuild changed crates (refetch if needed) | Refetch, regenerate and rebuild changed crates | Refetch and rebuild all crates | Refetch and rebuild all crates |
| Offline rebuild as long as | Not adding unfetched crate dependency | Not adding unfetched crate dependency | Not changing any dependencies | ✖ |
target_dir/CARGO_TARGET_DIR or sccache.nixpkgs integration for non-Rust package dependencies, cross-compilation (planned) and package overriding.rustc flags tweaking, arbitrary crate patching, force dynamic linking and more.cargo?Sorry, currently no. 😿 Updating of Cargo.lock still relies on cargo.
This can happen when creating a new project or changing dependencies.
We are mainly using cargo's SAT solver to pin down the dependency graph.
It's possible to implement it ourselves, but not yet, due to the complexity.
MIT Licensed.
Initial template generation and Cargo.lock updatin don't count for "code generation". The former is optional, and the latter is indeed not "code". ↩
Overall
Maintained
Code review
crates.io
Latest release
Releases this year
(top 24 of 37)
349 followers · starred Dec 2022
1,083 followers · starred Apr 2024
4,083 followers · starred Aug 2022
206 followers · starred Jul 2026
🚧 This project is under development and is not ready for production yet. APIs are subjects to change.
Build Rust crates with Nix Build System.
cargo dependency during building. Only rustc.[workspace]
membersmembersexcludes
FIXME: Buggy.resolver
Currently has custom resolution algorithm, more like v2.links[profile][{,dev-,build-}dependencies][features]
[target.<cfg>.dependencies][patch]
Automatically supported. Since the dependency graph Cargo.lock currently relies on cargo's generation.noc helper
noc init: Initial template flake.nix generation
registryregistry-indexgitpath inside workspacepath outside workspaceCargo.lock generation and updatingcachix and run cachix use nocargo (see more detail about cachix), orhttps://nocargo.cachix.org with public key nocargo.cachix.org-1:W6jkp5htZBA1tUdU8XHLaD7zBrIFnor0MsLhHgrJeHk=Cargo.lock already created by cargo.nix run github:oxalica/nocargo init to generate flake.nix. Or write it by hand by following the next section.nix flake show. Typically, the layout would be like,
└───packages
└───x86_64-linux
├───default: package 'rust_mypkg1-0.1.0' # The "default" package. For workspace, it's the top-level one if exists.
├───mypkg1: package 'rust_mypkg1-0.1.0' # Crate `mypkg1` with `release` profile.
├───mypkg1-dev: package 'rust_mypkg1-debug-0.1.0' # Crate `mypkg1` with `dev` profile.
├───mypkg2: package 'rust_mypkg2-0.1.0' # etc.
└───mypkg2-dev: package 'rust_mypkg2-debug-0.1.0'
nix build .#<pkgname> to build your package. Built binaries (if any) will be placed in ./result/bin, and the library will be in ./result/lib.flake.nix structure for referenceA template flake.nix with common setup are below. It's mostly the same as the generated one, except that the helper noc will scan the workspace and discover all external registries and git dependencies for you.
{
description = "My Rust packages";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
nocargo = {
url = "github:oxalica/nocargo";
inputs.nixpkgs.follows = "nixpkgs";
# See below.
# inputs.registry-crates-io.follows = "registry-crates-io";
};
# Optionally, you can explicitly import crates.io-index here.
# So you can `nix flake update` at any time to get cutting edge version of crates,
# instead of waiting `nocargo` to dump its dependency.
# Otherwise, you can simply omit this to use the locked registry from `nocargo`,
# which is updated periodically.
# registry-crates-io = { url = "github:rust-lang/crates.io-index"; flake = false; };
};
outputs = { nixpkgs, flake-utils, nocargo, ... }@inputs:
flake-utils.lib.eachSystem [ "x86_64-linux" ] (system:
let
# The entry API to make Nix derivations from your Rust workspace or package.
# The output of it consists of profile names, like `release` or `dev`, each of which is
# a attrset of all member package derivations keyed by their package names.
ws = nocargo.lib.${system}.mkRustPackageOrWorkspace {
# The root directory, which contains `Cargo.lock` and top-level `Cargo.toml`
# (the one containing `[workspace]` for workspace).
src = ./.;
# If you use registries other than crates.io, they should be imported in flake inputs,
# and specified here. Note that registry should be initialized via `mkIndex`,
# with an optional override.
extraRegistries = {
# "https://example-registry.org" = nocargo.lib.${system}.mkIndex inputs.example-registry {};
};
# If you use crates from git URLs, they should be imported in flake inputs,
# and specified here.
gitSrcs = {
# "https://github.com/some/repo" = inputs.example-git-source;
};
# If some crates in your dependency closure require packages from nixpkgs.
# You can override the argument for `stdenv.mkDerivation` to add them.
#
# Popular `-sys` crates overrides are maintained in `./crates-io-override/default.nix`
# to make them work out-of-box. PRs are welcome.
buildCrateOverrides = with nixpkgs.legacyPackages.${system}; {
# Use package id format `pkgname version (registry)` to reference a direct or transitive dependency.
"zstd-sys 2.0.1+zstd.1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = old: {
nativeBuildInputs = [ pkg-config ];
propagatedBuildInputs = [ zstd ];
};
# Use package name to reference local crates.
"mypkg1" = old: {
nativeBuildInputs = [ git ];
};
};
# We use the rustc from nixpkgs by default.
# But you can override it, for example, with a nightly version from https://github.com/oxalica/rust-overlay
# rustc = rust-overlay.packages.${system}.rust-nightly_2022-07-01;
};
in rec {
# For convenience, we hoist derivations of `release` and `dev` profile for easy access,
# with `dev` packages postfixed by `-dev`.
# You can export different packages of your choice.
packages = ws.release
// nixpkgs.lib.mapAttrs' (name: value: { name = "${name}-dev"; inherit value; }) ws.dev
// {
# The "default" features are turned on by default.
# You can `override` the library derivation to enable a different set of features.
# Explicit overriding will disable "default", unless you manually include it.
mypkg1-with-custom-features = (ws.release.mypkg1.override {
# Enables two features (and transitive ones), and disables "default".
features = [ "feature1" "feature2" ];
}).bin;
};
});
}
Main differences are already clarified on the top.
nocargo is inspired by cargo2nix and buildRustCrate in nixpkgs. We are more like cargo2nix while the generation part is implemented by pure Nix, but less like naersk which is a wrapper to call cargo to build the package inside derivations.
In other words, we and cargo2nix use Nix as a Build System, while nearsk use Nix as a Package Manager or Packager.
| nocargo | cargo2nix/buildRustCrate | naersk | buildRustPackage | |
|---|---|---|---|---|
Depend on cargo | Updating Cargo.lock | Updating & generating & building | Updating & vendoring & building | Building |
| Derivation granularity | Per crate | Per crate | Per package + one dependency closure | All in one |
| Crate level sharing | ✔️ | ✔️ | ✖ | ✖ |
| Binary substitution per crate | ✔️ | Not implemented | ✖ | ✖ |
| Code generation | ✖ | ✔️ | ✖ | ✖ |
| Edit workspace & rebuild | Rebuild leaf crates | Rebuild leaf crates | Rebuild leaf crates | Refetch and rebuild all crates |
| Edit dependencies & rebuild | Rebuild changed crates (refetch if needed) | Refetch, regenerate and rebuild changed crates | Refetch and rebuild all crates | Refetch and rebuild all crates |
| Offline rebuild as long as | Not adding unfetched crate dependency | Not adding unfetched crate dependency | Not changing any dependencies | ✖ |
target_dir/CARGO_TARGET_DIR or sccache.nixpkgs integration for non-Rust package dependencies, cross-compilation (planned) and package overriding.rustc flags tweaking, arbitrary crate patching, force dynamic linking and more.cargo?Sorry, currently no. 😿 Updating of Cargo.lock still relies on cargo.
This can happen when creating a new project or changing dependencies.
We are mainly using cargo's SAT solver to pin down the dependency graph.
It's possible to implement it ourselves, but not yet, due to the complexity.
MIT Licensed.
Initial template generation and Cargo.lock updatin don't count for "code generation". The former is optional, and the latter is indeed not "code". ↩
Overall
Maintained
Code review
crates.io
Latest release
Releases this year
(top 24 of 37)
349 followers · starred Dec 2022
1,083 followers · starred Apr 2024
4,083 followers · starred Aug 2022
206 followers · starred Jul 2026