Skip to content

Development Guides

Learn how to extend and customize your Nix configuration.


This section covers development workflows for customizing your Nix configuration. Learn to add packages, create modules, build profiles, and test changes before applying them.


Start here to install new software.

Covers:

  • Finding packages in nixpkgs
  • Adding system-wide packages
  • Adding user packages with Home Manager
  • Installing Homebrew casks
  • Custom package creation

Perfect for: Adding software to your system


Write custom Nix modules for reusable configuration.

Covers:

  • Module structure and basics
  • Defining module options
  • Conditional configuration
  • Platform-specific modules
  • Testing and validation

Perfect for: Building reusable configuration components


Build composable feature bundles.

Covers:

  • Profile vs module differences
  • Creating simple profiles
  • Role-based profiles (devops, security, ai-ml)
  • Language-specific profiles
  • Profile composition

Perfect for: Bundling related tools and configurations


Customize and modify packages using overlays.

Covers:

  • Overlay fundamentals
  • Overriding package versions
  • Applying patches
  • Adding custom packages
  • Python and language-specific overlays

Perfect for: Customizing existing packages


Test changes before applying to your system.

Covers:

  • Dry run builds
  • Diff analysis
  • Syntax validation
  • CI/CD integration
  • Troubleshooting builds

Perfect for: Safe system updates and development


Terminal window
# 1. Find package
nix search nixpkgs htop
# 2. Add to config
# In hosts/your-mac.nix:
environment.systemPackages = [ pkgs.htop ];
# 3. Apply
darwin-rebuild switch --flake .#your-hostname
Terminal window
# 1. Create profile file
cat > nix/profiles/my-tools.nix << 'EOF'
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
htop
ripgrep
fd
];
}
EOF
# 2. Add to flake.nix imports
imports = [ ./nix/profiles/my-tools.nix ];
# 3. Build and apply
darwin-rebuild switch --flake .#your-hostname
Terminal window
# Build without applying
darwin-rebuild build --flake .#your-hostname
# Check what changed
nix store diff-closures /run/current-system ./result
# Apply if good
darwin-rebuild switch --flake .#your-hostname

1. Search/create package
2. Test build locally
3. Add to system/user config
4. Test build (dry run)
5. Apply changes
1. Create module with options
2. Validate syntax
3. Test evaluation
4. Build system with module
5. Apply and verify
1. Identify related tools
2. Create profile file
3. Import in flake
4. Test build
5. Apply changes

Adding Packages

Quick:

environment.systemPackages = [ pkgs.package-name ];

Creating Profiles

Quick:

nix/profiles/my-profile.nix
{ pkgs, ... }: {
environment.systemPackages = with pkgs; [ tool1 tool2 ];
}

Working with Overlays

Quick:

nixpkgs.overlays = [(final: prev: {
mypackage = prev.mypackage.override { enableFeature = true; };
})];

Creating Modules

Quick:

{ config, lib, ... }: {
options.mymodule.enable = lib.mkEnableOption "my module";
config = lib.mkIf config.mymodule.enable { };
}

Testing Builds

Quick:

Terminal window
darwin-rebuild build --flake .#hostname
nix store diff-closures /run/current-system ./result

┌─────────────────────────────────────────────────────────────┐
│ Development Layers │
├─────────────────────────────────────────────────────────────┤
│ │
│ flake.nix │
│ │ │
│ ├─> Modules (nix/modules/) │
│ │ └─> Common, Darwin, Linux, Cloud │
│ │ │
│ ├─> Profiles (nix/profiles/) │
│ │ └─> Cloud-CLI, Developer, Hardware-Security │
│ │ │
│ ├─> Overlays (nix/overlays/) │
│ │ └─> Package customizations │
│ │ │
│ ├─> Packages (nix/packages/) │
│ │ └─> Custom packages │
│ │ │
│ └─> Hosts (hosts/) │
│ └─> Machine-specific configs │
│ │
└─────────────────────────────────────────────────────────────┘

Terminal window
# Always test first
darwin-rebuild build --flake .#hostname
nix store diff-closures /run/current-system ./result
darwin-rebuild switch --flake .#hostname
Terminal window
# Commit before major changes
git add .
git commit -m "Add new feature"
# Test
# If breaks: git reset --hard HEAD
nix/
├── modules/ # Low-level, configurable
├── profiles/ # High-level, opinionated
├── overlays/ # Package modifications
└── packages/ # Custom packages
# Good: Explain why
# Use Node 20 for compatibility with tool X
nodejs = prev.nodejs_20;
# Bad: No context
nodejs = prev.nodejs_20;
# ✅ Good: Clear and simple
environment.systemPackages = [ pkgs.htop ];
# ❌ Bad: Over-engineered
environment.systemPackages = lib.optionals
(config.enable.monitoring)
[ (if config.advanced then pkgs.htop-advanced else pkgs.htop) ];

Terminal window
# Show full error
nix build .#package --show-trace
# Keep failed build for inspection
nix build .#package --keep-failed
Terminal window
# Update flake
nix flake update
# Search again
nix search nixpkgs package-name
Terminal window
# Check module loads
nix eval .#darwinConfigurations.hostname.config.mymodule.enable
# Validate syntax
nix-instantiate --parse nix/modules/mymodule.nix

See Troubleshooting Guide for more.


nix/profiles/python-dev.nix
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
python3
python3Packages.pip
python3Packages.virtualenv
poetry
black
ruff
];
environment.variables = {
PYTHONPATH = "$HOME/.local/lib/python3.11/site-packages";
};
}
nix/profiles/cloud-dev.nix
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
# Cloud CLIs
awscli2
google-cloud-sdk
azure-cli
# Container tools
docker
kubectl
helm
# IaC
terraform
pulumi
];
}
nix/packages/my-tool.nix
{ pkgs, lib }:
pkgs.buildGoModule {
pname = "my-tool";
version = "1.0.0";
src = pkgs.fetchFromGitHub {
owner = "user";
repo = "my-tool";
rev = "v1.0.0";
sha256 = "sha256-...";
};
vendorHash = "sha256-...";
meta = {
description = "My custom tool";
license = lib.licenses.mit;
};
}

  1. Adding Packages - Start here
  2. Testing Builds - Learn safe updates
  3. Creating Profiles - Bundle tools
  1. Creating Modules - Build reusable config
  2. Working with Overlays - Customize packages
  3. Examples - Study real-world examples
  1. Design Philosophy - Understand architecture
  2. Structure Guide - Deep dive
  3. Nix Fundamentals - Master Nix



Ready to develop? Start with Adding Packages!