├── .gitignore ├── README.md ├── check.sh ├── configuration.nix ├── flake.lock ├── flake.nix └── hardware-configuration.nix /.gitignore: -------------------------------------------------------------------------------- 1 | result* 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nixos-flake-example 2 | 3 | ## warning 4 | 5 | **WARNING**: You should understand that: 6 | 7 | - there is currently no path to flakes being stable 8 | - we can't even experiment with flakes alternatives without committing to pure-eval as a stepping stone 9 | - the people that CARE about the problems solved by flakes seem to care about solving this problem 10 | - the people using impurity everywhere don't seem very motivated to dive into this problem-space 11 | - as a result, the tooling is completely fractured and stagnant 12 | - besides some UX fixes, bugfixes, and other feature-work in Nix, this has more or less been the case for years 13 | - I'm tired of seeing (often self-proclaimed, repeated-from-others) FUD by non-flakes users 14 | 15 | Anyway, now you know. Proceed at your own caution. 16 | 17 | ## overview 18 | 19 | **NOTE**: [nixflk](https://github.com/nrdxp/nixflk) is a better example repo for a full 20 | NixOS config layout, this repo is mostly to provide more context+examples around flakes, 21 | and to show that you can produce the same EXACT system with flakes as with nix-build, 22 | if you know what to do. 23 | 24 | This readme starts out with an attempt to explain and justify flakes. It also contains 25 | some examples of `nix` cli flakes syntax and tips for adopting flakes in your project. 26 | 27 | Finally, [at the end of the readme](#example-nixos-config-with-optional-flake-support) 28 | is an example NixOS config with a supporting `flake.nix`, 29 | and instructions to build it with *and without* flakes support at the same time. 30 | 31 | - [Overview of Flakes (and why you want it)](#overview-of-flakes-and-why-you-want-it) 32 | - [Important Related Reading](#important-related-reading) 33 | - [Nix CLI - Flakes Usage](#nix-cli---flakes-usage) 34 | - [Useful Commands and Examples](#useful-commands-and-examples) 35 | - [nixos-rebuild](#nixos-rebuild) 36 | - [nix build](#nix-build) 37 | - [nix flake](#nix-flake) 38 | - [Auto-coercion examples](#auto-coercion-examples) 39 | - [Tips for Porting to Flakes](#tips-for-porting-to-flakes) 40 | - [Example NixOS Config with optional Flake support](#example-nixos-config-with-optional-flake-support) 41 | 42 | ## Overview of Flakes (and why you want it) 43 | 44 | Flakes is a few things: 45 | * `flake.nix`: a Nix file, with a specific structure to describe inputs and outputs for a Nix project 46 | * See [NixOS Wiki - Flakes - Input Schema](https://nixos.wiki/wiki/Flakes#Input_schema) for flake input examples 47 | * See [NixOS Wiki - Flakes - Output Schema](https://nixos.wiki/wiki/Flakes#Input_schema) for flake output examples 48 | * `flake.lock`: a manifest that "locks" inputs and records the exact versions in use 49 | * CLI support for flake-related features 50 | * pure (by default) evaluations 51 | 52 | This ultimately enables: 53 | * properly hermetic builds 54 | * fully reproducable and portable Nix projects 55 | * faster Nix operations due to evaluation caching enabled by pure evaluations) 56 | 57 | This removes the need for: 58 | * using `niv` or other tooling to lock dependencies 59 | * manually documenting or scripting to ensure `NIX_PATH` is set consistently for your team 60 | * the need for the *"the impure eval tree of sorrow"* that comes with all of today's Nix impurities 61 | 62 | ## Important Related Reading 63 | 64 | * [NixOS Wiki - Flakes](https://nixos.wiki/wiki/Flakes) 65 | * a somewhat haphazard collection of factoids/snippets related to flakes 66 | * particularly look at: **[Flake Schema](https://nixos.wiki/wiki/Flakes#Flake_schema)**, and it's two sections: **[Input Schema](https://nixos.wiki/wiki/Flakes#Input_schema)**, **[Output Schema](https://nixos.wiki/wiki/Flakes#Output_schema)** 67 | * [Tweag - NixOS flakes](https://www.tweag.io/blog/2020-07-31-nixos-flakes/) 68 | * this article describes how to enable flake support in `nix` and `nix-daemon` 69 | * reading this article is a **pre-requisite** 70 | * this README.md assumes you've enabled flakes system-wide 71 | * omit using `boot.isContainer = true;` on `configuration.nix` (as the article suggests) if you want to use `nixos-rebuild` rather than `nixos-container` 72 | 73 | ## Nix CLI - Flakes Usage 74 | 75 | Nix is in flakes mode when: 76 | * `--flake` is used with the `nixos-rebuild` command 77 | * or, when `nix build` is used with an argument like `'.#something'` (the hash symbol separates the flake source from the attribute to build) 78 | 79 | When in this mode: 80 | * Nix flake commands will implicitly take a directory path, it expects a `flake.nix` inside 81 | * when you see: `nix build '.#something'`, the `.` means current directory, and `#something` means to build the `something` output attribute 82 | 83 | ### Useful Commands and Examples 84 | #### nixos-rebuild 85 | * `nixos-rebuild build --flake '.#'` 86 | * looks for `flake.nix` in `.` (current dir) 87 | * since it's `nixos-rebuild`, it automatically tries to build: 88 | * `#nixosConfigurations.{hostname}.config.system.build.toplevel` 89 | * `nixos-rebuild build --flake '/code/nixos-config#mysystem'` 90 | * looks for `flake.nix` in `/code/nixos-config` 91 | * since it's `nixos-rebuild`, it automatically tries to build: 92 | * `#nixosConfigurations.mysystem.config.system.build.toplevel` 93 | * (note that this time we specifically asked, and got to build the `mysystem` config) 94 | #### nix build 95 | * `nix build 'github:colemickens/nixpkgs-wayland#obs-studio'` 96 | * looks for `flake.nix` in (a checkout of `github.com/colemickens/nixpkgs-wayland`) 97 | * builds and run the first attribute found: 98 | * `#obs-studio` 99 | * `#packages.{currentSystem}.obs-studio` 100 | * TODO: finish fleshing out this list 101 | #### nix flake 102 | * `nix flake update --recreate-lock-file` 103 | * updates all inputs and recreating `flake.lock` 104 | * `nix flake update --update-input nixpkgs` 105 | * updates a single input to latest and recording it in `flake.lock` 106 | 107 | ### Auto-coercion examples 108 | 109 | Nix CLI will try to be ... smart and auto-coerce some output attribute paths for you. 110 | 111 | * `nix build '/some/path#obs-studio'`: 112 | * builds and run the first attribute found: 113 | * `/some/path#obs-studio` 114 | * `/some/path#packages.x86_64-linux.obs-studio` 115 | * `/some/path#legacyPackages.x86_64-linux.obs-studio` 116 | * TODO: finish fleshing out this list 117 | * TODO: not sure about search order, presumably the bare one would be priority 118 | 119 | ## Tips for Porting to Flakes 120 | 121 | **Remove Impurities** - Since nix flakes does a 'pure' build by default, 122 | * `NIX_PATH` is ignored 123 | * `` imports do not work, and explicitly error 124 | * local user nixpkgs config (`~/.config/{nix,nixpkgs}`) are ignore 125 | * unpinned imports (aka, `fetchTarball` without a pinned `rev`+`sha256`) are forbidden 126 | 127 | To fix these: 128 | * specify all remote imports in `flake.nix` instead of using `fetchTarball` 129 | * the config in this repo shows an example of using the overlay from 130 | `nixpkgs-wayland`. 131 | * TODO: investigate `getFlake` vs passing `inputs` in `specialArgs` 132 | 133 | ## Example NixOS Config with optional Flake support 134 | 135 | Consider the nixos configuration in this repo: 136 | * [./configuration.nix](./configuration.nix) 137 | * [./hardware-configuration.nix](./hardware-configuration.nix) 138 | 139 | These represent an example, minimal NixOS system configuration. 140 | 141 | The easiest way to build it, without cloning this repo: 142 | ``` 143 | nix build 'github:colemickens/nixos-flake-example#nixosConfigurations.mysystem.config.system.build.toplevel' 144 | ``` 145 | 146 | Let's prove that we can build this config, with and without flakes: 147 | 148 | * Using `nixos-rebuild`: 149 | ```shell 150 | # with flakes 151 | unset NIX_PATH 152 | nixos-rebuild build --flake '.#mysystem' 153 | readlink -f ./result 154 | /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git 155 | 156 | # !! for this next step, match the git SHA1 to what the flake.lock uses 157 | # otherwise you'll have a hash mismatch due to different nixpkgs 158 | 159 | # without flakes 160 | export NIX_PATH=nixpkgs=https://github.com/nixos/nixpkgs/archive/007126eef72271480cb7670e19e501a1ad2c1ff2.tar.gz:nixos-config=/home/cole/code/nixos-flake-example/configuration.nix 161 | nixos-rebuild build 162 | readlink -f ./result 163 | /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git 164 | ``` 165 | 166 | * Using `nix build`: 167 | ```shell 168 | # with flakes 169 | unset NIX_PATH 170 | nix build '.#nixosConfigurations.mysystem.config.system.build.toplevel 171 | readlink -f ./result 172 | /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git 173 | 174 | # without flakes 175 | export NIX_PATH=nixpkgs=https://github.com/nixos/nixpkgs/archive/007126eef72271480cb7670e19e501a1ad2c1ff2.tar.gz:nixos-config=/home/cole/code/nixos-flake-example/configuration.nix 176 | nix-build '' -A config.system.build.toplevel 177 | readlink -f ./result 178 | /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git 179 | ``` 180 | 181 | * The `./check.sh` script automates this process: 182 | 183 | ```shell 184 | cole@slynux ~/code/nixos-flake-example master* 7s 185 | ❯ ./check.sh 186 | 187 | :: Updating the 'nixpkgs' input in flake.nix 188 | + nix flake update --update-input nixpkgs 189 | + set +x 190 | 191 | :: Using 'nixos-rebuild' to build the 'mysystem' toplevel 192 | + nixos-rebuild build --flake '.#mysystem' 193 | warning: Git tree '/home/cole/code/nixos-flake-example' is dirty 194 | building the system configuration... 195 | warning: Git tree '/home/cole/code/nixos-flake-example' is dirty 196 | + set +x 197 | 198 | :: Using rev=007126eef72271480cb7670e19e501a1ad2c1ff2 for (extracted from flake.nix) 199 | 200 | :: Setting NIX_PATH to the same values flakes is using 201 | + NIX_PATH=nixpkgs=https://github.com/nixos/nixpkgs/archive/007126eef72271480cb7670e19e501a1ad2c1ff2.tar.gz:nixos-config=/home/cole/code/nixos-flake-example/configuration.nix 202 | + nix-build '' -A config.system.build.toplevel 203 | /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git 204 | + set +x 205 | 206 | flake: /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git 207 | clssc: /nix/store/gg1jhmzqndqa0rfnwfdbnzrn8f74ckr6-nixos-system-mysystem-21.03pre-git 208 | ``` 209 | 210 | # Flake Feedback/Ponderings 211 | 212 | - Is the hash tag syntax really worth it? 213 | - For example, is: 214 | - `nix build 'github:colemickens/nixpkgs-wayland#obs-studio'` 215 | - really better than: 216 | - `nix build --flake 'github:colemickens/nixpkgs-wayland' 'obs-studio'` ? 217 | 218 | - Are the auto-coercion rules for attribute paths worth it? 219 | They definitely add some mental overhead... 220 | 221 | - 222 | -------------------------------------------------------------------------------- /check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | rm -f result 5 | unset NIX_PATH 6 | 7 | echo 8 | echo ":: Updating the 'nixpkgs' input in flake.nix"; set -x 9 | nix flake update --update-input nixpkgs &>/dev/null 10 | set +x 11 | 12 | echo 13 | echo ":: Using 'nixos-rebuild' to build the 'mysystem' toplevel"; set -x 14 | nixos-rebuild build --flake '.#mysystem' 15 | set +x 16 | flake_path="$(readlink -f ./result)" 17 | 18 | # extract rev from flake.lock so we can figure out the nixpkgs rev used 19 | rev="$(cat flake.lock| jq -r '.nodes.nixpkgs.locked.rev')" 20 | echo 21 | echo ":: Using rev=${rev} for (extracted from flake.nix)"; set +x 22 | 23 | 24 | rm -f result 25 | nixpkgs="https://github.com/nixos/nixpkgs/archive/${rev}.tar.gz" 26 | nixosconfig="$(pwd)/configuration.nix" 27 | 28 | echo 29 | echo ":: Setting NIX_PATH to the same values flakes is using"; set -x 30 | NIX_PATH="nixpkgs=${nixpkgs}:nixos-config=${nixosconfig}" \ 31 | nix-build '' -A config.system.build.toplevel 32 | set +x 33 | 34 | # nixos-rebuild build 35 | 36 | classic_path="$(readlink -f ./result)" 37 | 38 | set +x 39 | echo 40 | echo "flake: ${flake_path}" 41 | echo "clssc: ${classic_path}" 42 | 43 | if [[ "${flake_path}" != "${classic_path}" ]]; then 44 | exit -1 45 | fi 46 | 47 | -------------------------------------------------------------------------------- /configuration.nix: -------------------------------------------------------------------------------- 1 | # Edit this configuration file to define what should be installed on 2 | # your system. Help is available in the configuration.nix(5) man page 3 | # and in the NixOS manual (accessible by running ‘nixos-help’). 4 | 5 | { config, pkgs, lib, modulesPath, inputs, ... }: 6 | 7 | { 8 | 9 | imports = [ 10 | ./hardware-configuration.nix 11 | ]; 12 | 13 | services.sshd.enable = true; 14 | 15 | networking.hostName = "mysystem"; 16 | 17 | nixpkgs.overlays = [ inputs.nur.overlay ]; 18 | 19 | environment.systemPackages = with pkgs; [ 20 | pkgs.nur.repos.mic92.hello-nur 21 | ]; 22 | } 23 | 24 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1603153815, 6 | "narHash": "sha256-uCav0CJ0Zm0vbqJiS9NUYD4XZg4Ww9bbsFzcDUzh2+U=", 7 | "owner": "nixos", 8 | "repo": "nixpkgs", 9 | "rev": "007126eef72271480cb7670e19e501a1ad2c1ff2", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "nixos", 14 | "ref": "nixos-unstable", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "nur": { 20 | "locked": { 21 | "lastModified": 1604808696, 22 | "narHash": "sha256-yJRRZEBzvfuDUMarWCbD6ehZd1u3rHqA9nK3OJOE30s=", 23 | "owner": "nix-community", 24 | "repo": "NUR", 25 | "rev": "3189c40da661eefc0c604f7f50df4956cf542a25", 26 | "type": "github" 27 | }, 28 | "original": { 29 | "owner": "nix-community", 30 | "repo": "NUR", 31 | "type": "github" 32 | } 33 | }, 34 | "root": { 35 | "inputs": { 36 | "nixpkgs": "nixpkgs", 37 | "nur": "nur" 38 | } 39 | } 40 | }, 41 | "root": "root", 42 | "version": 7 43 | } 44 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | 2 | { 3 | description = "An example NixOS configuration"; 4 | 5 | inputs = { 6 | nixpkgs = { url = "github:nixos/nixpkgs/nixos-unstable"; }; 7 | nur = { url = "github:nix-community/NUR"; }; 8 | }; 9 | 10 | outputs = inputs: 11 | /* ignore:: */ let ignoreme = ({config,lib,...}: with lib; { system.nixos.revision = mkForce null; system.nixos.versionSuffix = mkForce "pre-git"; }); in 12 | { 13 | nixosConfigurations = { 14 | 15 | mysystem = inputs.nixpkgs.lib.nixosSystem { 16 | system = "x86_64-linux"; 17 | modules = [ 18 | ./configuration.nix 19 | 20 | /* ignore */ ignoreme # ignore this; don't include it; it is a small helper for this example 21 | ]; 22 | specialArgs = { inherit inputs; }; 23 | }; 24 | }; 25 | }; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /hardware-configuration.nix: -------------------------------------------------------------------------------- 1 | # these args are passed into every nixos module (or file that is in included in a nixos module imports=[...]) 2 | { 3 | modulesPath, # this variable, in particular, gives us the nixos modules path for our system config 4 | ... 5 | }: 6 | 7 | { 8 | imports = [ 9 | # note: this format can't be used with flakes, because it pulls from 10 | # NIX_PATH, which is impure, and dis-allowed with flakes. 11 | # Use the format shown in the line below it. 12 | 13 | # 14 | 15 | "${modulesPath}/installer/scan/not-detected.nix" 16 | 17 | ]; 18 | boot.loader.systemd-boot.enable = true; # (for UEFI systems only) 19 | fileSystems."/".device = "/dev/disk/by-label/nixos"; 20 | } 21 | --------------------------------------------------------------------------------