← Back to Course Index
Lesson 7: Advanced Patterns
Overlays, Home Manager, system configuration, and beyond
Learning Objectives
- Understand overlays and how to customize packages
- Introduction to Home Manager for user config
- Understand NixOS system configuration declaratively
- Compose complex setups from simple pieces
Overlays: Customizing Packages
Sometimes you need a slightly modified version of a package. Overlays let you override or extend nixpkgs without forking it.
{
description = "Dev env with custom packages";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
# Define an overlay to customize packages
overlay = final: prev: {
myPython = prev.python3.withPackages (ps: with ps; [
numpy
pandas
requests
]);
};
pkgs = import nixpkgs {
inherit system;
overlays = [ overlay ];
};
in
{
devShells.default = pkgs.mkShell {
buildInputs = [ pkgs.myPython ];
};
}
);
}
Home Manager: Declarative User Config
Home Manager lets you manage your user dotfiles, shell settings, and packages declaratively using Nix. It works on any Linux/macOS, not just NixOS.
Home Manager use case: Define your entire user environment (shell, editor config, packages) in one file. Move to a new machine, run Home Manager, and you're set up exactly as before.
Example home configuration:
{ config, pkgs, ... }:
{
home.packages = with pkgs; [
git
neovim
tmux
htop
];
programs.zsh.enable = true;
programs.zsh.shellAliases = {
ll = "ls -la";
gs = "git status";
};
programs.git.enable = true;
programs.git.userName = "Your Name";
programs.git.userEmail = "you@example.com";
}
NixOS: System-Wide Configuration
If running NixOS, your entire system is declaratively configured via configuration.nix. This takes reproducibility to the OS level.
{ config, pkgs, ... }:
{
# System packages
environment.systemPackages = with pkgs; [
git
vim
gcc
];
# Enable services
services.openssh.enable = true;
services.postgresql.enable = true;
# Configure user
users.users.alice = {
isNormalUser = true;
extraGroups = [ "wheel" ];
packages = with pkgs; [
firefox
vscode
];
};
}
Composing Patterns
The real power emerges when you combine patterns:
- Project-level: flake.nix defines dev environment
- Team-level: Shared flakes ensure consistency
- User-level: Home Manager configures your tools
- System-level: NixOS configures the whole machine
The Nix stack: Everything is reproducible, version-controlled, and composable. You have a single source of truth for your entire computing environment.
Best Practices for Advanced Patterns
- Start simple: Master flakes before overlays
- Keep overlays small: Don't reinvent nixpkgs
- Use Home Manager incrementally: Add configs gradually
- Document your choices: Comments explain why you override packages
- Test thoroughly: Your system config affects everything
What's Possible Now
With these advanced patterns, you can:
- Share reproducible dev environments across your entire team
- Customize packages for your specific needs
- Manage your entire user environment declaratively
- Run an entire OS that's version-controlled and reproducible
- Move setups between machines in seconds
Key Takeaways
- Overlays customize packages without forking nixpkgs
- Home Manager brings declarative config to user level
- NixOS extends this to the entire system
- Composition is the power—small pieces combine into robust systems
- Everything is versionable—your whole setup can be in git