Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    0xbigboss

    nix-best-practices

    0xbigboss/nix-best-practices
    DevOps
    35

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Nix patterns for flakes, overlays, unfree handling, and binary overlays. Use when working with flake.nix or shell.nix.

    SKILL.md

    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:

    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:

    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.

    Recommended Servers
    Vercel Grep
    Vercel Grep
    Cloudflare Workers Observability
    Cloudflare Workers Observability
    vastlint - IAB XML VAST validator and linter
    vastlint - IAB XML VAST validator and linter
    Repository
    0xbigboss/claude-code
    Files