Nix Best Practices

作者 alleneubank2921eb8a685a無授權條款52 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫3 個月前更新

Use when working with Nix flakes, overlays, shell.nix, or flake.nix files.

AI 產生的概覽

撰寫 Nix flake、overlay、開發環境以及處理非自由軟體套件的參考指南。

功能
提供 Nix flake 結構、輸入 follows 鏈式引用、套用 overlay、處理非自由軟體套件、建立二進位 overlay 儲存庫、開發環境、direnv 整合以及常用指令的慣例與程式碼模式。也列出常見 flake 錯誤的疑難排解步驟,例如缺少輸入、非自由軟體套件失敗、重複下載 nixpkgs 和雜湊不符。它只是純說明性參考,不會產生檔案或指令碼。
適用情境
在撰寫或審查 flake.nix、shell.nix 或 overlay 定義時使用,也適合排查 Nix flake 錯誤。適合需要開發環境、overlay 和非自由軟體套件設定成熟模式的開發者。
執行需求
不附帶指令碼或工具,僅為說明性內容。依指南操作需要已啟用 flakes 的 Nix 環境,並需要網路存取以取得 flake 輸入和二進位檔。

Nix Best Practices

Flake Structure

Standard flake.nix structure:

nix
{  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:

nix
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:

nix
outputs = { self, nixpkgs, some-overlay, another-overlay, ... }:

Applying Overlays

Overlays modify or add packages to nixpkgs:

nix
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:

nix
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:

nix
{ allowUnfree = true; }

Option 3: Specific Packages (Flake)

nix
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)

nix
{  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

bash
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:

bash
nix-prefetch-url --type sha256 https://example.com/tool-linux-amd64-v1.0.0

Dev Shell Patterns

Basic Shell

nix
devShells.default = pkgs.mkShell {  buildInputs = with pkgs; [    nodejs    python3  ];
  shellHook = ''    echo "Dev environment ready"  '';};

With Environment Variables

nix
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)

nix
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:

bash
use flake

For unfree packages without nixpkgs-unfree:

bash
export NIXPKGS_ALLOW_UNFREE=1use flake --impure

Common Commands

bash
# Update all inputsnix flake update
# Update specific inputnix flake update some-input
# Check flake validitynix flake check
# Show flake metadatanix flake metadata
# Enter dev shellnix develop
# Run command in dev shellnix develop -c <command>
# Build packagenix build .#packageName
# Run packagenix run .#packageName

Troubleshooting

"unexpected argument" Error

All inputs must be listed in outputs function:

nix
# Wrongoutputs = { 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:

  1. nixpkgs-unfree input (recommended)
  2. User's ~/.config/nixpkgs/config.nix
  3. 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:

nix
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.

來源與署名

來源:alleneubank/claude-code位於.claude/skills/nix-best-practices提交2921eb8

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架