Nix: Getting started with Flakes
I've been using NixOS for a few months now, and so far I've avoided flakes and not really understood why to use flakes or what they are. These are my notes from attempting to set up an initial flake controlled NixOS installation.
What are flakes?
-
Channels: Exact package version info is derived from external state (channel configuration)
-
Flakes: Exact package version info is explicitly stated in config files that can be version controlled (
flake.lock
)
So that seems like an improvement. Channels have always seemed a bit iffy to me, given that you'd need to know which channels were used in order to reproduce a configuration.nix
otherwise.
Enabling flakes in NixOS
If flakes are not enabled in your config (they are disabled by default as an "experimental" feature as of 23.05), add this to your NixOS config (/etc/nixos/configuration.nix
by default):
nix.settings.experimental-features = [ "nix-command" "flakes"];
Run:
$ sudo nixos-rebuild switch
Now we have a nix install with flakes enabled.
Minimal flake
It just contains a description, an input
attr set and an output
attr set.
{
description = "My system configuration flake";
inputs = {};
outputs = {};
}
Inputs
Inputs is a set of git repos referencing nix package sets. Most obviously and importantly, we'll need nixpkgs
. For example like this to set up the 23.05 stable branch:
{
description = "My system configuration flake";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; # Could be simplified to nixpkgs/nixos-23.05 with builtin magic for nixpkgs.
};
outputs = {};
}
Outputs
Your system configuration
{
description = "My system configuration flake";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; # Could be simplified to nixpkgs/nixos-23.05 with builtin magic for nixpkgs.
};
outputs = {self, nixpkgs, ...}: {
nixosConfigurations = {
iron = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./iron/configuration.nix ];
};
};
};
}
Note it says nixosConfigurations in plural. You can specify multiple NixOS configurations, one for each host. For each host, you specify which system architecture it is, and which nix modules specify the system configuration.
Activating a flake
sudo nixos-rebuild switch --flake .
Forgotten files
If you get something like this, and are in a git repo - but you are referencing files which are not yet added and committed. Then you need to add and commit those files first:
$ nix flake update
error: getting status of '/nix/store/ad4s1wajy1dmadsx4xngw6kmva4dww1v-source/flake.nix': No such file or directory
In general, it seems that it's best to work from a clean git repo state, with everything committed.
Deploying flakes to a remote machine
nixos-rebuild switch --flake .#nixos-public-services --target-host [email protected]
Upgrading flakes
Pinned versions in flakes.lock
can be upgraded with nix flake update
. Note that this will only update the flakes.lock
file, not perform the actual upgrade, so it needs to be followed by nixos-rebuild switch --flake .
.
NixOS stable + Unstable + Home-manager
My actual configuration is a bit more complex. I want the ability to pull some packages from unstable (looking at you, signal, for expiring releases within months) and using the popular home-manager module:
{
description = "My system configuration flake";
inputs = {
nixpkgs.url = "nixpkgs/nixos-23.05";
unstable.url = "nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-23.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = {self, nixpkgs, unstable, home-manager, ...}: {
nixosConfigurations = {
iron = nixpkgs.lib.nixosSystem rec {
system = "x86_64-linux";
modules = let
defaults = { pkgs, ...}: {
_module.args.unstable = import unstable { inherit system; };
_module.args.home-manager = import home-manager.nixosModules.home-manager {};
}; in
[
defaults
./iron/configuration.nix
home-manager.nixosModules.home-manager
];
};
};
};
}
Prev: HlK-LD2410C radar presence sensors, MQTT and home assistant [DRAFT]