Overlay¶
Overview¶
An overlay is a function final: prev: { ... } that returns attribute overrides and new packages to merge into nixpkgs's fixed-point package set.
For fixed-point mechanics, stacking order, and extends, see Overlays Pattern. For install paths and longer how-tos, see Writing Overlays.
Details¶
Naming (final / prev vs self / super)¶
An overlay is a two-argument function. Newer code uses final and prev; older code often uses self and super. The roles are the same either way:
| Argument | Legacy name | Meaning |
|---|---|---|
final |
self |
The composed package set after this overlay and all later overlays—the fixed point |
prev |
super |
The set from nixpkgs and overlays before this one |
Use prev for the package you are replacing and for helpers already on the previous stage (callPackage, fetchFromGitHub, …). Use final for dependencies of packages you define or override so downstream code in the composed set sees the updated attrs. Swapping the two is a common footgun; see Overlays Pattern.
Composition order¶
Nixpkgs evaluates overlays left to right in the list. Each overlay extends the result of the previous ones. If two overlays both set the same top-level name, the later one wins. Put foundational pins (interpreters, BLAS/LAPACK providers, stdenv tweaks) before overlays that depend on those attrs via final.
import <nixpkgs> {
overlays = [
(final: prev: { python3 = prev.python312; }) # runs first
(final: prev: { myApp = prev.myApp.override { # runs second;
python3 = final.python3; # sees pinned python3
}; })
];
}
Under the hood, layers compose with lib.composeManyExtensions and lib.extends; details are in Overlays Pattern.
Shallow merge pitfall¶
Overlay results merge with shallow //, not deep recursion. A later overlay that sets a top-level attr replaces the entire value from an earlier overlay—nested keys are not merged.
# overlay 1
final: prev: { foo = { a = 1; version = "1.0"; }; }
# overlay 2 — replaces foo entirely; `a` is gone
final: prev: { foo = { b = 2; }; }
# composed top-level foo => { b = 2; } only
To keep nested keys, merge manually (prev.python3.pkgs // { myPkg = ...; }) or override a specific nested attr instead of replacing the whole parent set. This is the main structural footgun when stacking overlays.
Where to apply¶
| Mechanism | Scope / notes |
|---|---|
import nixpkgs { overlays = [ ... ]; } |
Project or one-off import; path-based overlay lookup is skipped when overlays is passed |
pkgs.extend / pkgs.appendOverlays |
Recompute the fixed point on an existing pkgs; costly—prefer overlays at import time |
NixOS nixpkgs.overlays |
System evaluation only; does not affect standalone nix-env or ad-hoc import <nixpkgs> unless you share the same list |
~/.config/nixpkgs/overlays.nix |
User list of overlays (used when overlays is not passed to import) |
~/.config/nixpkgs/overlays/ |
Directory of .nix files (lexicographic order); error if both this and overlays.nix exist |
<nixpkgs-overlays> on NIX_PATH |
Highest-priority path lookup when overlays is not passed |
Reuse one overlay list for NixOS and user config when you want nix-build, nix-shell, and the system to stay aligned. Full install paths and legacy packageOverrides are covered in Writing Overlays.
Overlays vs overrides¶
An overlay is set-level: it returns a fragment of pkgs that nixpkgs folds into the fixed point, so anything resolving through final.someAttr picks up your change. .override and .overrideAttrs are package-level: they adjust one derivation's function arguments or mkDerivation attrs and return a single new derivation—nothing else in pkgs changes unless you wire that value in.
Overlays often call .override / .overrideAttrs on prev packages to propagate a tweak set-wide (for example, swapping a BLAS provider or patching hello everywhere). See Overlay vs Override.
This page stays at the concept layer—overlay shape, naming, shallow merge, and common attachment points. Per-package overrides, fixed-point internals, and install-path how-tos are covered in the pages linked under See also.
Examples¶
To pin Python across the set:
Patching one package inside an overlay (same shape as ../meta/examples/overlay-snippet.nix):
At import time, pass a list to overlays:
import <nixpkgs> {
overlays = [
(final: prev: { myTool = prev.callPackage ./my-tool.nix { }; })
];
}
When a new package needs attrs from the composed set, pull them from final:
final: prev: {
myCli = prev.callPackage ./tools/my-cli.nix {
inherit (final) lib openssl python3;
};
}
References¶
- Nixpkgs manual — Overlays — chapter overview
- Nixpkgs manual — Defining overlays —
final/prev, return shape, canonical examples - Nixpkgs manual — Installing overlays — import, NixOS, path lookup,
overlays.nix - Nixpkgs manual — Overriding —
.overrideand.overrideAttrsused inside overlays
See also¶
- Overlay vs Override — set-level vs package-level scope
- Overlays Pattern — fixed point,
extends, shallow merge, anti-patterns - Writing Overlays — install paths, stacking, NixOS + user config
- Package Sets — how
pkgsis composed - Functional Package Management — why overlays fit the model
- overlay-snippet.nix — corpus fixture