Nix
Nix is a declarative package manager and build system. It lets you defined dependencies and configurations in a functional language, and uses build isolation to ensure consistend and reproducible builds across machines.
The declarative nature of Nix makes it great at dealing with complex environment. It handles cross-platform builds correctly. Despite being over 20 years old, it has recently gained a lot of support. It is useful for providing consistent development setups between teams, ensuring that the code has the same environments between developers, CI machines and deployment machines.
Nix is quite versatile. It can be used to configure your system, setup a hygienic development shell containing only the dependencies you explicitly requested, build Docker images with the minimal set of runtime dependencies.
Nix Explainer
What can you use Nix for?
Nix is a bit of an oddball in this section because it is more than just a build system. You can use it, or even combine it with other build systems. Some common setups are:
- Using Nix to define a development environment
- Using Nix to define CI tasks that can be easily run locally
- Using Nix as a build system
- Using Nix to deploy your application
Nix has great support for caching. This is one of the principal reasons why it is useful as a build system.
Nix Development Environment
The Rust project comes with rustup
, which you can use to manage your Rust
toolchains. It allows you to install multiple versions of Rust side-by-side,
update them, and select a toolchain version per-project. You can even put a
rust-toolchain.toml
file in your project root, and have rustup
pick this up
and select the appropriate toolchain for you. This is explained in the
Cargo chapter.
However, this doesn’t quite solve all of your environment needs. What if you need to have a specific C library in your environment? What if you need to have specific tooling in your environment? Rustup is great at managing Rust toolchains, that is the primary purpose it serves. But it will not manage all of your native dependencies.
This is where Nix comes in. With Nix, you can declaratively define an environment,
and you can use nix-shell
to spawn a new shell with everything declared
in that environment accessible. That way, you can declare which native dependencies
you need once, and make sure that no matter what platform your developers happen
to use, Nix can make sure that all requirements are satisfied.
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
naersk.url = "github:nix-community/naersk";
nixpkgs-mozilla = {
url = "github:mozilla/nixpkgs-mozilla";
flake = false;
};
};
outputs = { self, flake-utils, naersk, nixpkgs, nixpkgs-mozilla }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = (import nixpkgs) {
inherit system;
overlays = [
(import nixpkgs-mozilla)
];
};
toolchain = (pkgs.rustChannelOf {
rustToolchain = ./rust-toolchain;
sha256 = "";
# ^ After you run `nix build`, replace this with the actual
# hash from the error message
}).rust;
naersk' = pkgs.callPackage naersk {
cargo = toolchain;
rustc = toolchain;
};
in rec {
# For `nix build` & `nix run`:
defaultPackage = naersk'.buildPackage {
src = ./.;
};
# For `nix develop` (optional, can be skipped):
devShell = pkgs.mkShell {
nativeBuildInputs = [ toolchain ];
};
}
);
}
Example: Cargo and OpenSSL
Nix for Continuous Integration
https://nix-ci.com/
https://serokell.io/blog/continuous-delivery-with-nix
https://github.com/NixOS/hydra
https://hercules-ci.com/
Nix as a build system
Building C/C++ dependencies
Building TypeScript dependencies
Building WebAssembly component
https://jordankaye.dev/posts/rust-wasm-nix/
Nix for deployment
https://garnix.io/blog/hosting-nixos
https://x86.lol/generic/2024/08/28/systemd-sysupdate.html
Reading
Reference manual for the Nix package manager.
Rust in the NixOS Wiki
ipetkov/crane on GitHub
Building a Rust service with Nix by Amos Wenger
Amos shows how to build a Rust service in this article.
Introducing Crane: Composable and Cacheable Builds with Cargo and Nix by Ivan Petkov
Ivan introduces Crane in this article, a Nix library for building Cargo projects. He explains how it works and how to use it to build Rust projects.
Building Nix Flakes from Rust Workspaces by Tor Hovland
Tor explains how to package your Rust code using Nix. He explains the
different options you have for doing so: the Nix built-in buildRustPackage
,
Naersk, Crane and Cargo2Nix. He shows how to build a sample application that
consists of a Rust crate that is compiled into WebAssembly, a Rust library and
a Rust application that depends on both of these. He also discusses some
potential other options for building and packaging Rust code in Nix.
Zero to Nix by Determinate Systems
This is a guide on how to get started using Nix. It teaches you how to install it, how to use it for development, how to package your software with it, and how to manage your system with it.
https://jonathanlorimer.dev/posts/nix-thesis.html
https://jvns.ca/blog/2024/01/01/some-notes-on-nixos/
https://jvns.ca/blog/2023/03/03/how-do-nix-builds-work-/
https://jvns.ca/blog/2023/02/28/some-notes-on-using-nix/
Alternative Nix implementations:
https://tvix.dev/ https://lix.systems/about/