mcpField
N
nix-best-practices

nix-best-practices

github.com/alleneubank開発50548 回インストール18 週間前に更新
リポジトリ

nix-best-practices について

Nix Best Practices は、Nix flake、オーバーレイ、開発シェル、非フリーソフトウェアの設定を扱うリファレンススキルです。Nix プロジェクトの開発者向けに、コマンド例とトラブルシューティングを掲載しています。

主な機能

  1. 01flake の構成と入力の宣言
  2. 02follows による nixpkgs 入力の共有
  3. 03パッケージオーバーレイの適用
  4. 04非フリーパッケージの設定
  5. 05開発シェルと direnv の設定

活用シーン

  1. 01プロジェクト用 Nix flake の構築
  2. 02nixpkgs 入力の重複回避
  3. 03開発シェルでのネイティブ依存関係の提供
  4. 04flake やパッケージの一般的なエラーの調査

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/alleneubank/claude-code --skill nix-best-practices

インストール後、Claude Code で/nix-best-practicesを入力して読み込まれたか確認します。

詳細

Nix のベストプラクティス

Flake の構成

標準的な flake.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 パターン(Nixpkgs の重複を回避)

オーバーレイの入力を追加するときは、follows を使って親の nixpkgs を共有し、複数のバージョンのダウンロードを避けます:

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";
};

直接使用しない場合でも、すべての入力を outputs 関数に記載する必要があります:

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

オーバーレイの適用

オーバーレイは nixpkgs のパッケージを変更または追加します:

let
  pkgs = import nixpkgs {
    inherit system;
    overlays = [
      overlay1.overlays.default
      overlay2.overlays.default
      # Inline overlay
      (final: prev: {
        myPackage = prev.myPackage.override { ... };
      })
    ];
  };
in

非フリーパッケージの扱い

オプション 1:nixpkgs-unfree(チームにおすすめ)

ユーザー側の設定を必要とせずに EULA でライセンスされたパッケージを使用するには、numtide/nixpkgs-unfree を使います:

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";
};

これは次のようにつなぎます:proprietary-tool → nixpkgs-unfree → nixpkgs

オプション 2:ユーザー設定

ユーザーは ~/.config/nixpkgs/config.nix に追加します:

{ allowUnfree = true; }
オプション 3:特定のパッケージ(Flake)
let
  pkgs = import nixpkgs {
    inherit system;
    config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
      "specific-package"
    ];
  };
in

注:flake.nix の config.allowUnfree は nix develop では機能しません。nixpkgs-unfree またはユーザー設定を使ってください。

バイナリオーバーレイリポジトリの作成

nixpkgs でビルドしたコミュニティ版に機能が不足している場合(オープンコアのツールでよくあります)、公式バイナリを取得するオーバーレイを作成します。

パターン(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;
      };
    };
}
SHA256 ハッシュの取得
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>

または、SRI を直接使用します:

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

開発シェルのパターン

基本的なシェル
devShells.default = pkgs.mkShell {
  buildInputs = with pkgs; [
    nodejs
    python3
  ];

  shellHook = ''
    echo "Dev environment ready"
  '';
};
環境変数を使う場合
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)"
  '';
};
ネイティブ依存関係(C ライブラリ)
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 との統合

Flake プロジェクトの .envrc:

use flake

nixpkgs-unfree を使わずに非フリーパッケージを使用する場合:

export NIXPKGS_ALLOW_UNFREE=1
use flake --impure

よく使うコマンド

# 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

トラブルシューティング

「unexpected argument」エラー

すべての入力を outputs 関数に記載する必要があります:

# Wrong
outputs = { self, nixpkgs }: ...

# Right (if you have more inputs)
outputs = { self, nixpkgs, other-input, ... }: ...
nix develop での非フリーパッケージのエラー

flake.nix の config.allowUnfree は nix develop に引き継がれません。次のいずれかを使ってください:

  1. nixpkgs-unfree の入力(おすすめ)
  2. ユーザーの ~/.config/nixpkgs/config.nix
  3. NIXPKGS_ALLOW_UNFREE=1 nix develop --impure
Nixpkgs が重複してダウンロードされる

follows を使って、入力を単一の nixpkgs ソースにつなぎます。

オーバーレイが適用されない

nixpkgs をインポートするときに、オーバーレイが overlays リストに含まれていることを確認してください:

pkgs = import nixpkgs {
  inherit system;
  overlays = [ my-overlay.overlays.default ];
};
ハッシュの不一致

nix-prefetch-url で再取得し、ハッシュを更新します。上流で同じ URL のバイナリが更新されると、ハッシュも変わります。

コメント