nix-best-practices

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

INSTALLATION
npx skills add https://github.com/0xbigboss/claude-code --skill nix-best-practices
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

$27

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 ];

};

BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card