dotfiles.nix wiki
Welcome to the dotfiles.nix documentation.
Nix Knowledge
Package broken, PR merged but no update yet?
Track PR with: https://nixpk.gs/pr-tracker.html
Repository Structure
.
├── flake.nix # Entry point, input definitions, and output composition
├── lib/ # Custom Nix library functions
│ ├── default.nix # Library entry point
│ ├── scanPaths.nix # Recursive module discovery logic
│ └── helpers.nix # Flake helpers (makeOverlay, makePackages)
├── modules/ # Reusable modules
│ ├── shared/ # Cross-platform modules
│ │ ├── system/ # System-level config (e.g., core, packages)
│ │ └── home/ # Home Manager config (e.g., shell, editor)
│ └── darwin/ # macOS-specific modules
│ ├── system/ # macOS system settings
│ └── home/ # macOS Home Manager modules
└── hosts/ # Host-specific configurations
└── mac/ # Configuration for "mac" host
├── import-sys.nix # Recursive system import
└── import-hm.nix # Recursive home-manager import
External Usage
This flake exposes its modules for consumption by other configurations (like
nix-work), allowing for a layered configuration approach where dotfiles.nix
provides the base.
Exported Modules
sharedModules: Core system configuration, packages, and shared Home Manager modules.macModules: macOS-specific system modules and settings.
Output Structure
The flake outputs are structured to be easily consumed:
outputs = { ... }: {
sharedModules = [ ... ]; # Base modules
macModules = [ ... ]; # macOS modules
lib = { ... }; # Helper library
};
Example: nix-work Consumption
To build a work configuration on top of this base:
{
inputs.base.url = "github:ojsef39/dotfiles.nix";
outputs = { base, ... }: {
darwinConfigurations.workMac = darwin.lib.darwinSystem {
modules =
base.outputs.sharedModules
++ base.outputs.macModules
++ [
./work-specific-config.nix
];
specialArgs = {
baseLib = base.lib;
};
};
};
}
Remote building
(with 1Password as SSH Agent)
nix build .#darwinConfigurations.mac.system --builders 'ssh://<user>@<ip> x86_64-linux,aarch64-darwin'
Caution
Make sure you ran
sudo ssh <user>@<ip>first and accept the host key dialog, otherwise remote build will fail as that runs as root (nix daemon).This only works because of modules/darwin/system/system.nix:
activationScripts = {
preActivation.text = ''
plist="/Library/LaunchDaemons/systems.determinate.nix-daemon.plist"
desired="/Users/${vars.user.name}/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock"
current=$(/usr/libexec/PlistBuddy -c "Print :EnvironmentVariables:SSH_AUTH_SOCK" "$plist" 2>/dev/null || echo "")
if [ "$current" != "$desired" ]; then
/usr/libexec/PlistBuddy -c "Add :EnvironmentVariables dict" "$plist" 2>/dev/null || true
/usr/libexec/PlistBuddy -c "Set :EnvironmentVariables:SSH_AUTH_SOCK '$desired'" "$plist" 2>/dev/null || \
/usr/libexec/PlistBuddy -c "Add :EnvironmentVariables:SSH_AUTH_SOCK string '$desired'" "$plist"
if launchctl print system/systems.determinate.nix-daemon &>/dev/null; then
launchctl unload /Library/LaunchDaemons/systems.determinate.nix-daemon.plist
launchctl load /Library/LaunchDaemons/systems.determinate.nix-daemon.plist
fi
fi
'';
# example for linux
# systemd.services.nix-daemon = {
# environment = {
# SSH_AUTH_SOCK = "/run/user/${builtins.toString config.users.users.${username}.uid}/${
# config.home-manager.users.${username}.services.ssh-agent.socket
# }";
# };
# };
};
};
Setup & Deployment
This configuration is managed using nh (Nix Helper) and just.
#!/usr/bin/env just --justfile
alias d := deploy
alias u := upgrade
# macOS need nh darwin switch and NixOS needs nh os switch
nix_cmd := `if [ "$(uname)" = "Darwin" ]; then echo "darwin"; else echo "os"; fi`
nix_host := `if [ "$(uname)" = "Darwin" ]; then echo "mac"; else echo "nixos"; fi`
# Use GITHUB_TOKEN from 1Password to prevent rate limiting
nix_flags := `if [ "${GITHUB_ACTIONS:-}" != "true" ]; then echo '--option access-tokens github.com=$(op read op://Personal/GITHUB_TOKEN/no_access)'; fi`
[doc('HELP')]
default:
@just --list --list-prefix " " --list-heading $'🔧 Available Commands:\n'
[group('nix')]
[doc('Deploy system configuration')]
deploy: lint
# Deploying system configuration without update...
@git pull || true
@git add .
@nh {{nix_cmd}} switch -a -H {{nix_host}} $NIX_GIT_PATH -- {{nix_flags}}
[group('nix')]
[doc('Deploy system configuration')]
deploy-update: lint
# Deploying system configuration with update...
@git pull || true
@git add .
@nh {{nix_cmd}} switch -u -a -H {{nix_host}} $NIX_GIT_PATH -- {{nix_flags}}
[group('nix')]
[doc('Upgrade flake inputs and deploy')]
upgrade: update-refs lint
@git pull || true
@git add .
@nh {{nix_cmd}} switch -u -a -H {{nix_host}} $NIX_GIT_PATH -- {{nix_flags}}
@git add .
@if git log -1 --pretty=%B | grep -q "chore(deps): updated inputs and refs"; then \
echo "Amending previous dependency update commit..."; \
git commit --amend --no-edit || true; \
else \
git commit -m "chore(deps): updated inputs and/or refs" || true; \
fi
[group('nix')]
[doc('Update every fetcher with its newest commit and hash')]
update-refs:
# Update current repository
@kitten @ launch --type=overlay --title="update-nix-fetchgit-all" --copy-env --env SKIP_FF=1 fish -c "cd $NIX_GIT_PATH && update-nix-fetchgit-all"
[group('maintain')]
[doc('Clean and optimise the nix store with nh')]
clean:
@nh clean all -a -k 2 -K 7d
[group('maintain')]
[doc('Optimise the nix store')]
optimise:
@nix store optimise -v
[group('maintain')]
[doc('Verify and repair the nix-store')]
repair:
@sudo nix-store --verify --check-contents --repair || true
[group('maintain')]
[doc('Selectively rollback flake inputs')]
rollback:
@./scripts/flake-rollback.fish
[group('lint')]
[doc('Lint all nix files using statix and deadnix')]
lint: format
@nix run {{nix_flags}} nixpkgs#statix -- check .
@nix run {{nix_flags}} nixpkgs#deadnix -- -eq .
[group('lint')]
[doc('Format files using alejandra')]
format:
@nix run {{nix_flags}} nixpkgs#alejandra -- .
[group('lint')]
[doc('Show diff between current and commited changes')]
diff:
git diff ':!flake.lock'
Docker - Building container images with Nix
Example flake showing buildLayeredImage and buildImage with Ubuntu base.
Try it out
cd wiki/docker && nix develop -c $SHELL
or with nix-output-monitor
(nom develop -c $SHELL) for a nice overview of the build progress
This will build and load two Docker images:
nix-shell:latest- Pure Nix image using buildLayeredImageubuntu-nix:latest- Ubuntu base with Nix tools using buildImage
flake.nix
{
description = "Nix Docker image examples";
inputs = {
nixpkgs.url = "https://flakehub.com/f/JHOFER-Cloud/NixOS-nixpkgs/0.1.tar.gz"; # usually github:NixOS/nixpkgs/nixpkgs-unstable
flake-utils.url = "github:numtide/flake-utils";
};
outputs = {
nixpkgs,
flake-utils,
...
}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = nixpkgs.legacyPackages.${system};
# Get Linux packages - works on macOS with Determinate's built-in linux-builder
# This uses the linux-builder to build natively for Linux (fast, fully cached)
linuxPkgs = import pkgs.path {system = "x86_64-linux";};
# Alternative: Cross-compile to Linux (no cache, slower first build)
# linuxPkgs = pkgs.pkgsCross.musl64;
# Example 1: buildLayeredImage - pure Nix, from scratch
layeredImage = pkgs.dockerTools.buildLayeredImage {
name = "nix-shell";
tag = "latest";
contents = [linuxPkgs.busybox];
config.Cmd = ["/bin/sh"];
};
# Example 2: buildImage with Ubuntu base
ubuntuBase = pkgs.dockerTools.pullImage {
imageName = "ubuntu";
imageDigest = "sha256:cd1dba651b3080c3686ecf4e3c4220f026b521fb76978881737d24f200828b2b";
sha256 = "sha256-9vmJV6M21tZPk39lCCdCrwHR55gNzO1ka2De51IR9qs=";
finalImageTag = "24.04";
};
ubuntuImage = pkgs.dockerTools.buildImage {
name = "ubuntu-nix";
tag = "latest";
fromImage = ubuntuBase;
copyToRoot = pkgs.buildEnv {
name = "nix-tools";
paths = [linuxPkgs.busybox];
};
config.Cmd = ["/bin/sh"];
};
in {
devShells.default = pkgs.mkShell {
shellHook = ''
echo "Loading Docker images..."
if command -v podman &>/dev/null; then
podman load < ${layeredImage}
podman load < ${ubuntuImage}
elif command -v docker &>/dev/null; then
docker load < ${layeredImage}
docker load < ${ubuntuImage}
else
echo "No container runtime found"
exit 1
fi
echo "Images loaded: ${layeredImage.imageName}:${layeredImage.imageTag}, ${ubuntuImage.imageName}:${ubuntuImage.imageTag}"
'';
};
});
}
How it works
Linux Builder (Recommended)
The flake uses Determinate’s built-in Linux builder on macOS:
linuxPkgs = import pkgs.path {system = "x86_64-linux";};
This builds natively for Linux using the remote builder, which is fast and fully cached.
Cross-compilation Alternative
Alternatively, you can cross-compile using:
linuxPkgs = pkgs.pkgsCross.musl64;
Note: This approach has no binary cache, so first builds will be slower.