Skip to content

Bootstrap to Activation

This tutorial guides you through setting up a new machine with this infrastructure, teaching you the concepts behind each step so you can confidently work with the system going forward.

By the end of this tutorial, you will understand:

  • How Nix flakes provide reproducible, declarative system configuration
  • What the deferred module composition pattern is and why we organize modules by aspect rather than by host
  • How direnv automatically activates your development environment
  • What happens during system activation and how to verify success
  • How to explore your machine’s configuration and make sense of the module structure

Before starting, you need:

  • Physical or SSH access to a macOS or NixOS machine
  • Administrator privileges (sudo access)
  • Git installed and configured with your credentials
  • Internet connectivity for downloading packages

No prior Nix experience is required, but familiarity with command-line basics helps.

45-60 minutes for your first run through. Subsequent machines take 15-20 minutes once you understand the concepts.

Before touching the keyboard, let’s understand what we’re building toward.

Traditional system configuration involves installing packages manually, editing configuration files in /etc/, and hoping you remember what you changed when something breaks. Nix takes a different approach: your entire system configuration lives in version-controlled files, and the system state is derived from those files deterministically.

This means:

  • Reproducibility: The same configuration produces the same system, every time
  • Rollback: Every change creates a new generation you can roll back to
  • Declarative: You describe what you want, not how to get there

This infrastructure combines four complementary technologies:

  1. Flake-parts provides the foundation, organizing everything as composable modules
  2. Deferred module composition organizes modules by aspect (what they do) rather than by host (where they run)
  3. Clan-core coordinates multi-machine deployments with inventory-based service assignment
  4. Overlays provide stable fallbacks through multi-channel nixpkgs access

Module system foundation: The deferred module composition pattern uses deferred modules that delay evaluation until fixpoint computation. This enables the cross-cutting configuration patterns you’ll see below. See Deferred Module Composition for conceptual explanation.

You don’t need to understand all of this deeply right now. The key insight is that your machine configuration is just one piece of a larger, well-organized system.

For deeper understanding, see Architecture overview.

Traditional nix configs often organize by host: all of stibnite’s configuration in one place, all of blackphos’s in another. This leads to duplication when multiple machines need similar features.

The deferred module composition pattern instead organizes by aspect:

modules/
├── machines/ # Machine-specific configurations
│ ├── darwin/ # macOS hosts
│ └── nixos/ # NixOS hosts
├── home/ # User environment modules
│ ├── users/ # Per-user configurations
│ └── all/ # Shared user features
├── nixpkgs/ # Package customizations
└── clan/ # Multi-machine coordination

Each feature (git configuration, shell setup, development tools) lives in its own module. Machines compose these modules to build their complete configuration.

For the full explanation, see Deferred Module Composition.

Let’s start by getting the configuration onto your machine.

Terminal window
cd ~/projects # Or wherever you keep your code
git clone https://github.com/cameronraysmith/vanixiets.git
cd vanixiets

Take a moment to explore the structure:

Terminal window
ls -la

You’ll see:

  • flake.nix - The entry point defining all outputs
  • modules/ - The deferred module composition hierarchy
  • secrets/ - Encrypted secrets (we’ll cover this in the secrets tutorial)
  • justfile - Task runner with common operations
  • Makefile - Bootstrap automation

The flake.nix file is intentionally minimal because most logic lives in the auto-discovered modules. This is the deferred module composition pattern at work.

The bootstrap process installs Nix (if needed) and sets up direnv for automatic environment activation.

Terminal window
make bootstrap

This command:

  1. Checks if Nix is installed, installs it via the Determinate Systems installer if not
  2. Installs direnv for automatic development shell activation
  3. Configures your shell to use direnv

Why the Determinate Systems installer? It provides a cleaner installation with better macOS integration than the official installer, particularly for multi-user setups and Apple Silicon Macs.

Why direnv? When you enter a directory with a .envrc file, direnv automatically activates the appropriate environment. You get the right tools, environment variables, and shell configuration without remembering to run anything.

After bootstrap completes, restart your shell or run:

Terminal window
source ~/.zshrc # or ~/.bashrc

Now activate the development environment:

Terminal window
direnv allow

The first time takes a few minutes as Nix downloads and builds the development shell. You’ll see output as packages are fetched from the cache or built locally.

Once complete, your prompt may change (depending on your shell configuration), and you’ll have access to all the tools defined in the flake’s devShells.

Verify the environment:

Terminal window
which just
which darwin-rebuild # On macOS
which nixos-rebuild # On NixOS

These commands should point to paths inside /nix/store/, confirming the development shell is active.

Step 4: Explore your machine configuration

Section titled “Step 4: Explore your machine configuration”

Before activating, let’s understand what configuration will be applied.

Machines are defined in the clan inventory and have corresponding module directories:

Terminal window
# Darwin machines
ls modules/machines/darwin/
# NixOS machines
ls modules/machines/nixos/

The current fleet includes:

  • Darwin: stibnite, blackphos, rosegold, argentum
  • NixOS: cinnabar, electrum, galena, scheelite

Find your machine’s directory. If your machine isn’t listed, you’ll need to create a configuration first; see the Host Onboarding Guide.

Open your machine’s main configuration file. For a darwin machine like stibnite:

Terminal window
cat modules/machines/darwin/stibnite/default.nix

You’ll see imports of various modules. These imports follow the deferred module composition pattern, pulling in features from across the module hierarchy rather than defining everything inline.

Notice how the file is relatively short. Most configuration comes from:

  • Aggregate modules that bundle related features
  • User modules that define personal environments
  • Shared modules that all machines inherit

Pick one import and follow it. For example, if you see an import of an aggregate module:

Terminal window
cat modules/home/users/crs58/default.nix

This shows how a user’s environment is composed from smaller, focused modules. Each module handles one concern (git, shell, development tools), making the system easier to understand and modify.

Always validate your configuration builds before activating:

For darwin machines:

Terminal window
nix build .#darwinConfigurations.stibnite.system --dry-run

Replace stibnite with your hostname. The --dry-run flag shows what would be built without actually building.

For NixOS machines:

Terminal window
nix build .#nixosConfigurations.cinnabar.config.system.build.toplevel --dry-run

If validation succeeds with no errors, you’re ready to activate.

Now apply the configuration to your system.

For darwin machines:

Terminal window
darwin-rebuild switch --flake .#stibnite

Or use the just task:

Terminal window
just activate

The just activate command auto-detects your platform and hostname.

For NixOS machines managed by clan:

Terminal window
clan machines update cinnabar

The activation process:

  1. Builds the complete system configuration from your flake
  2. Creates a new system generation in /nix/store
  3. Switches symlinks to point to the new generation
  4. Runs activation scripts (creating users, starting services, etc.)

This is a transactional operation. If something fails, your previous generation remains intact.

After activation completes:

Terminal window
# Check the current generation
darwin-rebuild --list-generations | head -5 # macOS
nixos-rebuild --list-generations | head -5 # NixOS
# Verify a package is available
which git
git --version
# Check home-manager status (if you have user configuration)
home-manager generations | head -3

If you configured zerotier, verify network connectivity:

Terminal window
sudo zerotier-cli listnetworks

You’ve now completed your first bootstrap-to-activation cycle. Along the way, you learned:

  • Nix flakes provide reproducible, declarative system configuration
  • Deferred module composition groups modules by aspect, reducing duplication
  • direnv automatically activates your development environment
  • Validation before activation catches errors before they affect your system
  • Generations provide rollback safety for every change

Now that your machine is activated, you should:

  1. Set up secrets if you haven’t already. The Secrets Setup Tutorial walks you through secrets management with clan vars and legacy sops-nix.

  2. Understand your user configuration by reading through your user module in modules/home/users/.

  3. Explore the guides for operational tasks:

  4. Deepen your understanding with the concepts documentation:

If your prompt doesn’t change after direnv allow:

Terminal window
# Ensure direnv hook is in your shell config
grep direnv ~/.zshrc # or ~/.bashrc
# If missing, add it
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
source ~/.zshrc

This usually means a flake input was updated but not locked:

Terminal window
nix flake update
nix flake check

Ensure your development shell is active:

Terminal window
cd /path/to/infra
direnv allow
which darwin-rebuild

You need administrator privileges:

Terminal window
sudo darwin-rebuild switch --flake .#hostname

For comprehensive troubleshooting, see the Host Onboarding Guide.