Overlays
In the previous section, we learned about overriding derivations using the override
keyword. However, this approach only affects the local derivation and doesn't modify the original derivation in pkgs
. To globally modify derivations in pkgs
, Nix provides a feature called "overlays".
In traditional Nix environments, overlays can be configured globally using the ~/.config/nixpkgs/overlays.nix
or ~/.config/nixpkgs/overlays/*.nix
files. However, in Flakes, to ensure system reproducibility, overlays cannot rely on configurations outside of the Git repository.
When using Flakes to configure NixOS, both Home Manager and NixOS provide the nixpkgs.overlays
option to define overlays. You can refer to the following documentation for more details:
Let's take a look at an example module that loads overlays. This module can be used as a Home Manager module or a NixOS module, as the definitions are the same:
{ config, pkgs, lib, ... }:
{
nixpkgs.overlays = [
# Overlay 1: Use `self` and `super` to express
# the inheritance relationship
(self: super: {
google-chrome = super.google-chrome.override {
commandLineArgs =
"--proxy-server='https=127.0.0.1:3128;http=127.0.0.1:3128'";
};
})
# Overlay 2: Use `final` and `prev` to express
# the relationship between the new and the old
(final: prev: {
steam = prev.steam.override {
extraPkgs = pkgs: with pkgs; [
keyutils
libkrb5
libpng
libpulseaudio
libvorbis
stdenv.cc.cc.lib
xorg.libXcursor
xorg.libXi
xorg.libXinerama
xorg.libXScrnSaver
];
extraProfile = "export GDK_SCALE=2";
};
})
# Overlay 3: Define overlays in other files
# The content of overlay3.nix is the same as above:
# `(final: prev: { xxx = prev.xxx.override { ... }; })`
(import ./overlays/overlay3.nix)
];
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
In the above example, we define three overlays. Overlay 1 modifies the google-chrome
derivation by adding a command-line argument for a proxy server. Overlay 2 modifies the steam
derivation by adding extra packages and an environment variable. Overlay 3 is defined in a separate file overlay3.nix
.
You can write your own overlays following this example. Import the configuration as a NixOS module or a Home Manager module, and then deploy it to see the effect.
Modular overlays
In the previous example, all overlays were written in a single Nix file, which can become difficult to maintain over time. To address this, we can manage overlays in a modular way.
Start by creating an overlays
folder in your Git repository to store all overlay configurations. Inside this folder, create a default.nix
file with the following content:
# import all nix files in the current folder,
# and execute them with args as parameters
# The return value is a list of all execution results,
# which is the list of overlays
args:
# execute and import all overlay files in the current
# directory with the given args
builtins.map
# execute and import the overlay file
(f: (import (./. + "/${f}") args))
# find all overlay files in the current directory
(builtins.filter
(f: f != "default.nix")
(builtins.attrNames (builtins.readDir ./.)))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
The default.nix
file imports and executes all Nix files in the current folder (excluding default.nix
) with the provided arguments. It returns a list of all overlay results.
Next, write your overlay configurations in the overlays
folder. For example, you can create overlays/fcitx5/default.nix
with the following content:
{ pkgs, config, lib, ... }:
(self: super: {
# Customized rime-data package
rime-data = ./rime-data-flypy;
fcitx5-rime = super.fcitx5-rime.override {
rimeDataPkgs = [ ./rime-data-flypy ];
};
})
2
3
4
5
6
7
8
9
In the above example, we override the rime-data
package with a custom version and modify the fcitx5-rime
derivation to use the custom rime-data
package.
To load all overlays returned by overlays/default.nix
, add the following parameter to any NixOS module:
{ config, pkgs, lib, ... } @ args:
{
# ...
nixpkgs.overlays = import /path/to/overlays/dir;
# ...
}
2
3
4
5
6
7
8
9
For instance, you can add it directly in flake.nix
:
{
description = "NixOS configuration of Ryan Yin";
# ...
inputs = {
# ...
};
outputs = inputs@{ self, nixpkgs, ... }:
{
nixosConfigurations = {
nixos-test = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = inputs;
modules = [
./hosts/nixos-test
# add the following inline module definition
# here, all parameters of modules are passed to overlays
(args: { nixpkgs.overlays = import ./overlays args; })
# ...
];
};
};
};
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
By using this modular approach, you can conveniently organize and manage your overlays. In this example, the structure of the overlays
folder would look like this:
.
├── flake.lock
├── flake.nix
├── home
├── hosts
├── modules
├── ...
├── overlays
│ ├── default.nix # return a list of all overlays.
│ └── fcitx5 # fcitx5 overlay
│ ├── default.nix
│ ├── README.md
│ └── rime-data-flypy # my custom rime-data
│ └── share
│ └── rime-data
│ ├── ...
└── README.md
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
This modular approach simplifies the management of overlays and allows you to easily add, modify, or remove overlays as needed.