Nix Best Practices Flake Structure Standard flake.nix structure: { description = "Project description" ; inputs = { nixpkgs . url = "github:NixOS/nixpkgs/nixos-unstable" ; flake - utils . url = "github:numtide/flake-utils" ; } ; outputs = { self , nixpkgs , flake - utils } : flake - utils . lib . eachDefaultSystem ( system : let pkgs = import nixpkgs { inherit system ; } ; in { devShells . default = pkgs . mkShell { buildInputs = with pkgs ; [
packages here
] ; } ; } ) ; } Follows Pattern (Avoid Duplicate Nixpkgs) When adding overlay inputs, use follows to share the parent nixpkgs and avoid downloading multiple versions: inputs = { nixpkgs . url = "github:NixOS/nixpkgs/nixos-unstable" ;
Overlay follows parent nixpkgs
some
overlay . url = "github:owner/some-overlay" ; some - overlay . inputs . nixpkgs . follows = "nixpkgs" ;
Chain follows through intermediate inputs
another
overlay . url = "github:owner/another-overlay" ; another - overlay . inputs . nixpkgs . follows = "some-overlay" ; } ; All inputs must be listed in outputs function even if not directly used: outputs = { self , nixpkgs , some - overlay , another - overlay , . . . } : Applying Overlays Overlays modify or add packages to nixpkgs: let pkgs = import nixpkgs { inherit system ; overlays = [ overlay1 . overlays . default overlay2 . overlays . default
Inline overlay
( final : prev : { myPackage = prev . myPackage . override { . . . } ; } ) ] ; } ; in Handling Unfree Packages Option 1: nixpkgs-unfree (Recommended for Teams) Use numtide/nixpkgs-unfree for EULA-licensed packages without requiring user config: inputs = { nixpkgs . url = "github:NixOS/nixpkgs/nixos-unstable" ; nixpkgs - unfree . url = "github:numtide/nixpkgs-unfree/nixos-unstable" ; nixpkgs - unfree . inputs . nixpkgs . follows = "nixpkgs" ;
Unfree overlay follows nixpkgs-unfree
proprietary
tool . url = "github:owner/proprietary-tool-overlay" ; proprietary - tool . inputs . nixpkgs . follows = "nixpkgs-unfree" ; } ; This chains: proprietary-tool → nixpkgs-unfree → nixpkgs Option 2: User Config Users add to ~/.config/nixpkgs/config.nix : { allowUnfree = true ; } Option 3: Specific Packages (Flake) let pkgs = import nixpkgs { inherit system ; config . allowUnfreePredicate = pkg : builtins . elem ( lib . getName pkg ) [ "specific-package" ] ; } ; in Note: config.allowUnfree in flake.nix doesn't work with nix develop - use nixpkgs-unfree or user config. Creating Binary Overlay Repos When nixpkgs builds a community version lacking features (common with open-core tools), create an overlay that fetches official binaries. Pattern (see 0xBigBoss/atlas-overlay, 0xBigBoss/bun-overlay) { inputs = { nixpkgs . url = "github:NixOS/nixpkgs/nixos-unstable" ; flake - utils . url = "github:numtide/flake-utils" ; } ; outputs = { self , nixpkgs , flake - utils } : flake - utils . lib . eachDefaultSystem ( system : let pkgs = nixpkgs . legacyPackages . $ { system } ; version = "1.0.0" ;
Platform-specific binaries
sources
{ "x86_64-linux" = { url = "https://example.com/tool-linux-amd64-v $ { version } " ; sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" ; } ; "aarch64-linux" = { url = "https://example.com/tool-linux-arm64-v $ { version } " ; sha256 = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" ; } ; "x86_64-darwin" = { url = "https://example.com/tool-darwin-amd64-v $ { version } " ; sha256 = "sha256-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=" ; } ; "aarch64-darwin" = { url = "https://example.com/tool-darwin-arm64-v $ { version } " ; sha256 = "sha256-DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD=" ; } ; } ; source = sources . $ { system } or ( throw "Unsupported system: $ { system } " ) ; toolPackage = pkgs . stdenv . mkDerivation { pname = "tool" ; inherit version ; src = pkgs . fetchurl { inherit ( source ) url sha256 ; } ; sourceRoot = "." ; dontUnpack = true ; installPhase = '' mkdir -p $out/bin cp $src $out/bin/tool chmod +x $out/bin/tool '' ; meta = with pkgs . lib ; { description = "Tool description" ; homepage = "https://example.com" ; license = licenses . unfree ;
or appropriate license
platforms
builtins . attrNames sources ; } ; } ; in { packages . default = toolPackage ; packages . tool = toolPackage ; overlays . default = final : prev : { tool = toolPackage ; } ; } ) // { overlays . default = final : prev : { tool = self . packages . $ { prev . system } . tool ; } ; } ; } Getting SHA256 Hashes nix-prefetch-url https://example.com/tool-linux-amd64-v1.0.0
Returns hash in base32, convert to SRI format:
nix hash to-sri --type sha256 < base32-hash
Or use SRI directly: nix-prefetch-url --type sha256 https://example.com/tool-linux-amd64-v1.0.0 Dev Shell Patterns Basic Shell devShells . default = pkgs . mkShell { buildInputs = with pkgs ; [ nodejs python3 ] ; shellHook = '' echo "Dev environment ready" '' ; } ; With Environment Variables devShells . default = pkgs . mkShell { buildInputs = with pkgs ; [ postgresql ] ;
Set at shell entry
DATABASE_URL
"postgres://localhost/dev" ;
Or in shellHook for dynamic values
shellHook
'' export PROJECT_ROOT="$(pwd)" '' ; } ; Native Dependencies (C Libraries) devShells . default = pkgs . mkShell { buildInputs = with pkgs ; [ openssl postgresql ] ;
Expose headers and libraries
shellHook
'' export C_INCLUDE_PATH=" $ { pkgs . openssl . dev } /include:$C_INCLUDE_PATH" export LIBRARY_PATH=" $ { pkgs . openssl . out } /lib:$LIBRARY_PATH" export PKG_CONFIG_PATH=" $ { pkgs . openssl . dev } /lib/pkgconfig:$PKG_CONFIG_PATH" '' ; } ; Direnv Integration .envrc for flake projects: use flake For unfree packages without nixpkgs-unfree: export NIXPKGS_ALLOW_UNFREE = 1 use flake --impure Common Commands
Update all inputs
nix flake update
Update specific input
nix flake update some-input
Check flake validity
nix flake check
Show flake metadata
nix flake metadata
Enter dev shell
nix develop
Run command in dev shell
nix develop -c < command
Build package
nix build .
packageName
Run package
nix run .
packageName
Troubleshooting "unexpected argument" Error All inputs must be listed in outputs function:
Wrong
outputs
{ self , nixpkgs } : . . .
Right (if you have more inputs)
outputs
{ self , nixpkgs , other - input , . . . } : . . . Unfree Package Errors with nix develop config.allowUnfree in flake.nix doesn't propagate to nix develop . Use: nixpkgs-unfree input (recommended) User's ~/.config/nixpkgs/config.nix NIXPKGS_ALLOW_UNFREE=1 nix develop --impure Duplicate Nixpkgs Downloads Use follows to chain inputs to a single nixpkgs source. Overlay Not Applied Ensure overlay is in the overlays list when importing nixpkgs: pkgs = import nixpkgs { inherit system ; overlays = [ my - overlay . overlays . default ] ; } ; Hash Mismatch Re-fetch with nix-prefetch-url and update the hash. Hashes change when upstream updates binaries at the same URL.