Testing Builds
Learn how to test Nix builds before applying changes to your system.
Table of Contents
Section titled “Table of Contents”- Overview
- Dry Run Builds
- Build Testing
- Diff Analysis
- Syntax Validation
- Package Testing
- CI/CD Integration
- Troubleshooting
Overview
Section titled “Overview”Testing builds before applying them:
- Catches errors early
- Shows what will change
- Validates syntax and logic
- Prevents system breakage
Dry Run Builds
Section titled “Dry Run Builds”Build Without Applying
Section titled “Build Without Applying”# Build but don't activatedarwin-rebuild build --flake .#your-hostname
ls -l ./result
What You Get
Section titled “What You Get”# result/ contains the system closureresult/├── sw/ # System packages├── activate # Activation script└── ...
# Inspect packagesls result/sw/bin/
Check What Changed
Section titled “Check What Changed”# Compare with current systemnix store diff-closures /run/current-system ./result
# Output shows added/removed packages and size changes
Build Testing
Section titled “Build Testing”Test Specific Package
Section titled “Test Specific Package”# Build single packagenix build .#ai-clis
# Build and inspectnix build .#ai-clis && ls ./result/bin/
Test Configuration
Section titled “Test Configuration”# Build full configurationnix build .#darwinConfigurations.your-hostname.system
# Verbose outputnix build .#darwinConfigurations.your-hostname.system --print-build-logs
Test Different Systems
Section titled “Test Different Systems”# Build for specific architecturenix build .#darwinConfigurations.your-hostname.system --system aarch64-darwin
# Cross-compile (if supported)nix build .#darwinConfigurations.your-hostname.system --system x86_64-darwin
Diff Analysis
Section titled “Diff Analysis”Show Package Changes
Section titled “Show Package Changes”# Detailed diffnix store diff-closures /run/current-system ./result
# Example output:# nodejs: 18.0.0 → 20.0.0 (+15.2 MB)# python3: ∅ → 3.11.0 (+50.0 MB)# vim: 9.0.0 → ε (removed)
Analyze Size Impact
Section titled “Analyze Size Impact”# Show closure sizenix path-info -S ./result
# Compare sizesecho "Current: $(nix path-info -S /run/current-system | awk '{print $2}')"echo "New: $(nix path-info -S ./result | awk '{print $2}')"
List All Changes
Section titled “List All Changes”# All packages in new buildnix-store -q --tree ./result
# Just added packagescomm -13 \ <(nix-store -q --references /run/current-system | sort) \ <(nix-store -q --references ./result | sort)
# Just removed packagescomm -23 \ <(nix-store -q --references /run/current-system | sort) \ <(nix-store -q --references ./result | sort)
Syntax Validation
Section titled “Syntax Validation”Flake Check
Section titled “Flake Check”# Comprehensive checksnix flake check
# Check specific systemnix flake check --system aarch64-darwin
# Show all outputsnix flake show
Parse Nix Files
Section titled “Parse Nix Files”# Check syntaxnix-instantiate --parse file.nix
# Evaluate (but don't build)nix-instantiate --eval file.nix
# Evaluate with strict modenix-instantiate --eval --strict file.nix
Validate Module
Section titled “Validate Module”# Check module is loadablenix eval .#darwinConfigurations.your-hostname.config.mymodule.enable
# Show module optionsnix eval .#darwinConfigurations.your-hostname.options.mymodule --json | jq
Package Testing
Section titled “Package Testing”Evaluate Package
Section titled “Evaluate Package”# Show package metadatanix eval .#mypackage.meta.description
# Show versionnix eval .#mypackage.version
# Show derivationnix derivation show .#mypackage
Build Package Locally
Section titled “Build Package Locally”# Build packagenix build .#mypackage
# Run from result./result/bin/mypackage --version
# Install to test profilenix profile install .#mypackage
# Test, then removenix profile remove mypackage
Test Package Dependencies
Section titled “Test Package Dependencies”# Show runtime dependenciesnix-store -q --references ./result
# Show build dependenciesnix-store -q --requisites $(nix-instantiate -A mypackage)
# Dependency treenix-store -q --tree ./result
CI/CD Integration
Section titled “CI/CD Integration”GitHub Actions
Section titled “GitHub Actions”name: Build Nix Configuration
on: pull_request: push: branches: [main]
jobs: build: runs-on: macos-latest steps: - uses: actions/checkout@v3
- uses: DeterminateSystems/nix-installer-action@main
- name: Build configuration run: | nix build .#darwinConfigurations.your-hostname.system
- name: Check flake run: | nix flake check
- name: Show diff if: github.event_name == 'pull_request' run: | # Compare with main branch git fetch origin main nix build github:${{ github.repository }}/main#darwinConfigurations.your-hostname.system -o result-main nix store diff-closures ./result-main ./result
GitLab CI
Section titled “GitLab CI”build: image: nixos/nix script: - nix build .#darwinConfigurations.your-hostname.system - nix flake check
test: image: nixos/nix script: - nix build .#ai-clis - ./result/bin/claude-code --version
Pre-commit Hooks
Section titled “Pre-commit Hooks”repos: - repo: local hooks: - id: nix-flake-check name: Nix flake check entry: nix flake check language: system pass_filenames: false
- id: nix-format name: Nix format entry: nix fmt language: system files: \.nix$
Troubleshooting
Section titled “Troubleshooting”Build Fails
Section titled “Build Fails”# Show full build lognix build .#mypackage --print-build-logs
# Show tracenix build .#mypackage --show-trace
# Keep failed buildnix build .#mypackage --keep-failed
# Failed build at:# /tmp/nix-build-mypackage-1.0.0.drv-0
Evaluation Errors
Section titled “Evaluation Errors”# Debug evaluationnix eval .#darwinConfigurations.your-hostname --show-trace
# Check specific attributenix eval .#darwinConfigurations.your-hostname.config.environment.systemPackages --json
Dependency Issues
Section titled “Dependency Issues”# Why is package included?nix why-depends ./result nixpkgs#python3
# Show dependency pathnix-store -q --tree ./result | grep python3 -B5
Cache Misses
Section titled “Cache Misses”# Check what needs to buildnix build .#mypackage --dry-run
# Build without substitutes (force local build)nix build .#mypackage --option substitute false
# Use specific cachenix build .#mypackage --option substituters "https://cache.nixos.org"
Testing Workflows
Section titled “Testing Workflows”Safe Update Workflow
Section titled “Safe Update Workflow”# 1. Backup current generationdarwin-rebuild --list-generations
# 2. Update flake locknix flake update
# 3. Build (don't apply)darwin-rebuild build --flake .#your-hostname
# 4. Check diffnix store diff-closures /run/current-system ./result
# 5. If looks good, applydarwin-rebuild switch --flake .#your-hostname
# 6. If something breaks, rollbackdarwin-rebuild switch --rollback
Package Development Workflow
Section titled “Package Development Workflow”# 1. Create packagevim nix/packages/mypackage.nix
# 2. Quick syntax checknix-instantiate --parse nix/packages/mypackage.nix
# 3. Test buildnix build .#mypackage
# 4. Test executable./result/bin/mypackage
# 5. Iteratevim nix/packages/mypackage.nixnix build .#mypackage --rebuild
# 6. Add to systemenvironment.systemPackages = [ pkgs.mypackage ];
Module Testing Workflow
Section titled “Module Testing Workflow”# 1. Create modulevim nix/modules/mymodule.nix
# 2. Validate syntaxnix-instantiate --parse nix/modules/mymodule.nix
# 3. Check module loadsnix eval .#darwinConfigurations.your-hostname.config.mymodule.enable
# 4. Build with moduledarwin-rebuild build --flake .#your-hostname
# 5. Check what changednix store diff-closures /run/current-system ./result
# 6. Apply if gooddarwin-rebuild switch --flake .#your-hostname
Best Practices
Section titled “Best Practices”Always Test First
Section titled “Always Test First”# ❌ Bad: Direct applydarwin-rebuild switch --flake .#hostname
# ✅ Good: Test firstdarwin-rebuild build --flake .#hostnamenix store diff-closures /run/current-system ./resultdarwin-rebuild switch --flake .#hostname
Use Version Control
Section titled “Use Version Control”# ✅ Good: Commit before major changesgit add .git commit -m "WIP: testing new package"darwin-rebuild build --flake .#hostname# If fails, easy to revertgit reset --hard HEAD
Document Test Results
Section titled “Document Test Results”# ✅ Good: Save diff outputnix store diff-closures /run/current-system ./result > changes.txtgit add changes.txtgit commit -m "Add mypackage" -m "$(cat changes.txt)"
Test on Branches
Section titled “Test on Branches”# ✅ Good: Use git branchesgit checkout -b test-new-feature# Make changesdarwin-rebuild build --flake .#hostname# Test# If good: merge, if bad: delete branch
Quick Reference
Section titled “Quick Reference”Essential Commands
Section titled “Essential Commands”# Build without applyingdarwin-rebuild build --flake .#hostname
# Show diffnix store diff-closures /run/current-system ./result
# Validate configurationnix flake check
# Test packagenix build .#package && ./result/bin/package
# Show what needs buildingnix build .#hostname --dry-run
# Rollback if neededdarwin-rebuild switch --rollback
Next Steps
Section titled “Next Steps”- Adding Packages - Install software
- Creating Modules - Write modules
- Working with Overlays - Customize packages
- Troubleshooting - Fix issues
Related Documentation
Section titled “Related Documentation”- CLI Commands - Command reference
- Nix Fundamentals - Understanding builds
- Structure Guide - Config architecture
External References
Section titled “External References”- Nix Manual - Testing - Build commands
- nix-darwin Manual - Darwin-rebuild
- Nix Pills - Deep dives
Ready to test builds? Start with a dry run!