NixOS configuration for the thinkpad, managed via flakes with Home Manager for dotfiles.
- Fresh NixOS install (USB boot, minimal ISO)
- Git available (
nix-shell -p gitif not yet installed)
Clone the required repos:
mkdir -p ~/git/cwage
cd ~/git/cwage
git clone git@github.com:cwage/nix-workstation.git
git clone git@github.com:cwage/dotfiles.git
git clone git@github.com:cwage/bin.gitBuild and activate:
cd ~/git/cwage/nix-workstation
sudo nixos-rebuild switch --flake .#thinkpadEdit files in hosts/thinkpad/ or flake.nix, then:
sudo nixos-rebuild switch --flake .#thinkpadEdit files in ~/git/cwage/dotfiles, then update the flake lock and rebuild:
cd ~/git/cwage/nix-workstation
nix flake update dotfiles
sudo nixos-rebuild switch --flake .#thinkpad# Dry run - evaluate only, don't build or activate
nixos-rebuild dry-build --flake .#thinkpad
# Build without activating (test that it compiles)
nixos-rebuild build --flake .#thinkpad
# Build and activate, but don't add to bootloader (reverts on reboot)
sudo nixos-rebuild test --flake .#thinkpad
# Build and switch (activate + set as boot default)
sudo nixos-rebuild switch --flake .#thinkpadAll packages are pinned to a specific nixpkgs commit via flake.lock. Nothing changes on your running system until you rebuild.
# Update all flake inputs (nixpkgs, home-manager, dotfiles)
nix flake update
# Or update only nixpkgs (keeps other inputs pinned)
nix flake update nixpkgsYou can't update a single package independently — they all come from the same pinned nixpkgs commit. If you need a specific version of one package ahead of nixpkgs, use an overlay in flake.nix.
After updating flake.lock, build without activating, then use nvd to see a version diff (similar to apt-get -s upgrade):
nixos-rebuild build --flake .#thinkpad
nvd diff /run/current-system resultIf you're happy with the changes:
sudo nixos-rebuild switch --flake .#thinkpadTo roll back if something breaks:
sudo nixos-rebuild switch --rollbackPackages defined in pkgs/ are pinned to an upstream version with one or more content hashes. These hashes are not the same as anything GitHub displays — Nix unpacks the source and re-hashes it in NAR (Nix archive) format, so you can't just paste a release SHA from a GitHub release page.
Most packages have at least:
- A source
hashinsidefetchFromGitHub/fetchurl/ etc. — hash of the unpacked source tree. - A dependency-closure hash, named per ecosystem:
- Go:
vendorHash(vendored Go modules) - Rust:
cargoHash/cargoLock - Node:
npmDepsHash,pnpmDeps.hash,yarnDeps.hash - Python: varies by builder
- Go:
The dependency-closure hash changes whenever the lockfile (go.sum, Cargo.lock, etc.) changes upstream, even across patch releases.
Two workflows, pick whichever:
1. nix-update (easiest): automates version bump + hash recompute.
nix-update --flake --version 0.2.2 agentpen2. Fake-hash dance (manual, always works): edit the package file, bump version, replace each hash with lib.fakeHash (add lib to the function args if needed), then rebuild. Nix will fail with the actual hash in the error message — paste it back in. Repeat for each hash field.
src = fetchFromGitHub {
# ...
rev = "v${version}";
hash = lib.fakeHash; # rebuild, copy real hash from error, paste here
};
vendorHash = lib.fakeHash; # same danceThen rebuild as normal:
sudo nixos-rebuild switch --flake .#thinkpadnix-workstation/
├── flake.nix # Root flake (nixpkgs, home-manager, dotfiles inputs)
├── flake.lock # Pinned input versions
└── hosts/
└── thinkpad/
├── default.nix # Host entry point (hostname, imports)
├── configuration.nix # System config (packages, services, users)
└── hardware-configuration.nix # Hardware-specific (generated, machine-specific)
- The dotfiles flake input currently uses a local
path:reference. It will be switched togithub:cwage/dotfilesonce the dotfiles repo changes are pushed. - Home Manager symlinks dotfiles into the Nix store, so dotfile edits require a rebuild to take effect.
hardware-configuration.nixis machine-specific and generated bynixos-generate-config.