Nix and NixOS: Reproducible Builds and Dev Environments
In this tutorial, you'll learn Nix including the Nix package manager, declarative configuration, dev shells for reproducible environments, and using Nix for CI/CD and deployment.
Why Nix Matters
Traditional package managers install software globally, leading to dependency conflicts and "works on my machine" problems. Nix takes a fundamentally different approach: every package and its dependencies are identified by a cryptographic hash and stored in isolation. This means you can have multiple versions of the same package, reproduce environments exactly, and never worry about conflicts.
By the end of this guide, you will install and use the Nix package manager, create reproducible development shells, and understand how NixOS uses the same principles for system configuration.
What is Nix?
Nix is a purely functional package manager. Each package build is isolated, deterministic, and identified by a unique hash derived from its build inputs. The same Nix expression always produces the same result, anywhere.
flowchart LR A[Nix Expression] --> B[Derivation] B --> C[Hash: abc123] C --> D[Store Path: /nix/store/abc123-python-3.12] D --> E[Build Inputs] D --> F[Build Script] E --> G[Dependencies] G --> H[Also in /nix/store/] B --> I[Reproducible Build]
Installation
# Single-user install (recommended for developers)
sh <(curl -L https://nixos.org/nix/install)
# Multi-user install
sh <(curl -L https://nixos.org/nix/install) --daemon
After installation, source the Nix environment:
source ~/.nix-profile/etc/profile.d/nix.sh
Expected Output
$ nix --version
nix (Nix) 2.24.0
Basic Package Management
Installing Packages
# Install a package
nix-env -iA nixpkgs.ripgrep
# Install multiple packages
nix-env -iA nixpkgs.jq nixpkgs.fd nixpkgs.bat
# Search for packages
nix search nixpkgs python
# List installed packages
nix-env -q
# Upgrade packages
nix-env -u
# Remove a package
nix-env -e ripgrep
Expected Output
$ nix search nixpkgs python | head -5
* python3 (python3-3.12.2)
An interpreted, interactive, object-oriented programming language
* python311 (python3-3.11.8)
An interpreted, interactive, object-oriented programming language
Garbage Collection
# Remove unused packages
nix-collect-garbage
# List store paths
nix-store --gc --print-dead
# Clean older generations
nix-collect-garbage -d
Declarative Package Management
Instead of installing packages imperatively, Nix lets you define environments declaratively.
~/.config/nixpkgs/config.nix
{
packageOverrides = pkgs: let
myPackages = with pkgs; [
git
neovim
ripgrep
fd
jq
bat
tmux
htop
nodejs_20
python312
go
rustc
cargo
];
in {
myEnv = pkgs.buildEnv {
name = "my-env";
paths = myPackages;
};
};
}
nix-env -iA nixpkgs.myEnv
Development Shells (shell.nix)
The most powerful Nix feature for developers is the reproducible development shell.
Basic Development Shell
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
python312
python312Packages.pip
python312Packages.virtualenv
nodejs_20
nodePackages.pnpm
git
];
shellHook = ''
echo "Welcome to the development shell!"
echo "Python: $(python --version)"
echo "Node: $(node --version)"
'';
}
nix-shell
Expected Output
$ nix-shell
Welcome to the development shell!
Python: Python 3.12.2
Node: v20.11.0
[nix-shell:/home/user/project]$
All dependencies are available inside the shell. When you exit (exit or Ctrl-D), nothing remains.
Python Project Shell
# shell.nix
{ pkgs ? import <pkgs> {} }:
let
pythonEnv = pkgs.python312.withPackages (ps: with ps; [
flask
requests
pytest
black
mypy
]);
in pkgs.mkShell {
buildInputs = [
pythonEnv
pkgs.poetry
];
shellHook = ''
export PIP_REQUIRE_VIRTUALENV=false
'';
}
Rust Development Shell
# shell.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = with pkgs; [
rustc
cargo
rust-analyzer
rustfmt
clippy
pkg-config
openssl
];
RUST_BACKTRACE = 1;
shellHook = ''
echo "Rust development environment"
rustc --version
'';
}
Flakes (Nix 2.4+)
Flakes are a modern way to manage Nix expressions with lock files for reproducibility.
# flake.nix
{
description = "A development environment";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = nixpkgs.legacyPackages.${system};
in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
nodejs_20
python312
go
rustc
];
};
});
}
nix develop
Expected Behavior
With flakes, the exact versions of all dependencies are locked in flake.lock. Running nix develop on any machine at any time produces the same environment.
NixOS
NixOS is a Linux distribution built on the Nix package manager. The entire system -- packages, services, kernel modules, and configuration -- is declared in a single /etc/nixos/configuration.nix file.
# /etc/nixos/configuration.nix
{ config, pkgs, ... }:
{
imports = [ ./hardware-configuration.nix ];
boot.loader.systemd-boot.enable = true;
boot.loader.efi.canTouchEfiVariables = true;
# Users
users.users.alice = {
isNormalUser = true;
extraGroups = ["wheel" "docker"];
shell = pkgs.zsh;
};
# Packages
environment.systemPackages = with pkgs; [
git
vim
htop
curl
wget
docker
docker-compose
];
# Services
services.openssh.enable = true;
services.docker.enable = true;
services.nginx.enable = true;
# Security
networking.firewall.allowedTCPPorts = [ 80 443 22 ];
}
# Apply configuration
sudo nixos-rebuild switch
# Build and test (does not activate)
sudo nixos-rebuild test
# Upgrade
sudo nixos-rebuild switch --upgrade
Nix in CI/CD
# .github/workflows/ci.yml
name: CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v25
- run: nix-build
- run: nix-shell --run "npm test"
Comparison to Other Tools
| Feature | Nix | Docker | Homebrew | apt |
|---|---|---|---|---|
| Isolation | Full (per-package) | Container level | None | None |
| Reproducibility | Deterministic | Deterministic with lock | Approximate | Approximate |
| Multiple versions | Yes | Separate images | No | No |
| System config | NixOS | No | No | No |
| Dev shell | Yes | Yes (with volumes) | No | No |
| Learning curve | Steep | Moderate | Low | Low |
Common Errors
| Problem | Cause | Fix |
|---|---|---|
error: path '...' is not a valid store path |
Hash mismatch | Check nixpkgs channel is up to date: nix-channel --update |
error: Package 'python3-3.12' is not available |
Package not in selected channel | Use a newer channel or override with nixpkgs-unstable |
error: unpacker appears to have produced no instructions |
Corrupted download | Run nix-store --verify --check-contents |
nix-shell: command not found |
Nix not in PATH | Source the profile: source ~/.nix-profile/etc/profile.d/nix.sh |
cannot build 'derivation' on 'x86_64-linux' |
Wrong platform | Add system = "x86_64-linux" or use flake-utils |
Practice Questions
1. Where does Nix store packages?
In /nix/store/ with unique hash-based paths.
2. What is a shell.nix file used for?
It defines a reproducible development environment with specific packages and environment variables.
3. How do you enter a Nix development shell?
Run nix-shell in a directory containing shell.nix.
4. What is a Nix flake?
A modern Nix project format with locked dependencies for reproducibility.
5. What is NixOS?
A Linux distribution where the entire system configuration is defined declaratively in a single Nix file.
Challenge
Create a shell.nix for a full-stack JavaScript and Python project that includes: Node.js 20, Python 3.12 with Flask and pytest, PostgreSQL client tools, Redis CLI, and git. Add environment variables for development mode and a shell hook that prints the available tools.
Real-World Task
Set up a Nix development shell for an existing project. Identify all the tools and libraries the project needs and declare them in shell.nix. Remove all globally installed tools related to the project and verify that everything works inside nix-shell alone. Add flake support and lock the dependencies.
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro