Skip to content

Flake Design

Both systems use a pure flake design with no channels. This page documents the patterns and decisions behind the flake configuration.

Dual-Flake Architecture

Rather than a single monorepo flake with multiple nixosConfigurations, this repo uses two independent flakes: one in laptop/ and one in server/. Each has its own lock file and its own set of pinned inputs.

Why separate flakes?

  • The laptop and server have different update cadences. The laptop tracks bleeding-edge packages; the server prioritises stability.
  • Updating flake.lock for one system cannot break the other.
  • Each system can use different versions of the same input (e.g. lanzaboote v1.0.0 on laptop, v0.4.2 on server).

Input Pinning Strategy

Unstable + Stable Mix

Both systems use nixos-unstable as their primary nixpkgs, but pin a stable channel for specific packages that need it:

nix
# Laptop
nixpkgs.url = "nixpkgs/nixos-unstable";
nixpkgs-stable.url = "nixpkgs/nixos-25.11";

# Server
nixpkgs.url = "nixpkgs/nixos-unstable";
nixpkgs-stable.url = "nixpkgs/nixos-25.05";

The laptop uses the stable pin for AppFlowy:

nix
inputs.nixpkgs-stable.legacyPackages.${pkgs.system}.appflowy

Input Follows

Inputs that depend on nixpkgs use follows to avoid pulling in duplicate nixpkgs instances:

nix
disko = {
  url = "github:nix-community/disko";
  inputs.nixpkgs.follows = "nixpkgs";
};

The server's agenix input explicitly drops Darwin support to avoid pulling unused dependencies:

nix
agenix = {
  url = "github:ryantm/agenix";
  inputs.darwin.follows = "";
};

Binary Caches

The laptop configures the Chaotic-Nyx binary cache to avoid building the CachyOS kernel from source:

nix
substituters = [
  "https://cache.nixos.org"
  "https://chaotic-nyx.cachix.org"
];

trusted-public-keys = [
  "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
  "chaotic-nyx.cachix.org-1:HfnXSw4pj95iI/n17rIDy40agHj12WfF+Gqk6SonIT8="
];

The server uses only the default NixOS cache and disables signature verification (require-sigs = false) for local builds.

Experimental Features

Both systems enable the same core features:

nix
experimental-features = [ "nix-command" "flakes" ];

The laptop additionally enables recursive-nix and fetch-closure:

nix
experimental-features = [ "nix-command" "flakes" "recursive-nix" "fetch-closure" ];

Download Buffer

Both systems increase the download buffer to 500 MB for faster large package downloads:

nix
download-buffer-size = 524288000;  # 500 MB

Garbage Collection

The two systems use different GC strategies:

Laptop -- uses the nh tool for declarative cleanup:

nix
programs.nh.clean = {
  enable = true;
  dates = "weekly";
  extraArgs = "--keep-since 3d --keep 3";
};

Server -- uses the built-in Nix GC plus store optimisation:

nix
nix.gc = {
  automatic = true;
  dates = "weekly";
  options = "--delete-older-than 7d";
};

nix.optimise = {
  automatic = true;
  dates = [ "weekly" ];
};

Rebuilding

Laptop

The nh tool is configured with the flake path:

nix
programs.nh.flake = "/home/nixos/nixos-config/laptop";

So rebuilding is simply:

bash
nh os switch

Or manually:

bash
sudo nixos-rebuild switch --flake /home/nixos/nixos-config/laptop#laptop

Server

The server defines shell aliases in bash.nix:

bash
update    # nix flake update
rebuild   # sudo nixos-rebuild switch

It also has automated weekly upgrades via system.autoUpgrade (see Updates & Upgrades).

Built with VitePress