Flakes are notoriously hard to explain. So we aren’t starting with flakes. First, build the common channel-based world they tidy up:
Put the three independent Nix files onto the table.
Three files, each reaching outside the project on its own.
Place every file, then hit the update below the table. Notice what just happened: none of your files changed, and yet every package version in them moved at once.
Each of those files reached out to the moving <nixpkgs> channel living outside
the project, which is how an awful lot of real Nix code still works.
Now, plain Nix can absolutely be pinned, so the problem was never “no flakes means no reproducibility”. The problem is that the shared pin is easy to leave out and very hard for the next person to spot.
A flake drags three jobs back into the project itself.
flake.nix names what comes in and what the project offers, and
flake.lock remembers exactly what came in.
The nice part is that one front door can then offer a NixOS system, a Home Manager home, a package, or a development shell. The Nix sitting behind it is still perfectly ordinary Nix.
Four things decide what a project builds, and they don’t all live in the same place, which is most of why flakes feel slippery at first.
Pair each one with what it is responsible for.
flake.nixflake.lockconnect each item to its job
The top two travel with the repository. The bottom two do not, and that is the whole difference you just watched play out on the table.
Start with an output, then complete its path to a CLI command.
Inputs
Outputs
CLI
No inputs locked yet
Start with an output. Its broken wire will tell you which input to go and fetch,
and once you add that input, flake.lock unfolds underneath: the moving source
on the left, the exact saved revision it landed on over on the right.
Try older and newer under the lock. Every saved revision moves together,
and the package versions under each output follow along behind. Those buttons
stand in for reviewing an older or newer flake.lock. Real lockfiles do not come
with buttons, sadly.
Once the picture clicks, open flake editing mode under the table. Keep moving pieces around on the left and watch the same idea turn into Nix on the right.
If I update my system, does the side project I haven’t touched in six months still build?
0f4a1c84b8e2d773aa986e7d5f3160cd2b3Each project has its own flake.lock, so updating one moves only that one. The others stay on the revisions they were already building against.
Three projects, all of them depending on nixpkgs, none of them agreeing about which nixpkgs. Watch them for a moment and you’ll see the revisions never move together, because there is nothing they share for an update to travel along.
With a channel you depend on state that lives outside the project entirely, which
is why one update back in the first step dragged every file along with it. A
flake locks its dependencies inside the project, the way Cargo.lock or
package-lock.json does. Update the machine on Tuesday and the work
project carries on building against the revision it was happy with, until the day
you go into that folder and ask it to move.
Connect nixpkgs 26.05 to a NixOS system.
Inputs
Outputs
CLI
No inputs locked yet
Build the old path first, then swap out only nixos-26.05 for nixos-unstable.
The NixOS output and nixos-rebuild both stay exactly where they were. What
changes is the source feeding them, the exact revision it locks to, and every
package version that follows from it.
That whole stable-to-unstable exercise, as one real file:
inputs.nixpkgs is the piece you swapped. nixosConfigurations.castle is the
output that stayed put. nixos-rebuild --flake .#castle is the command that
comes asking for it.
The exact revision is missing on purpose, because Nix writes that into
flake.lock for you. You edit the moving intent in flake.nix, and the
generated lock records what that intent actually resolved to.
One thing that catches people out later: if this flake is backed by Git, its
source only includes files Git knows about. Add a new module and Nix may not see
it until you git add it.
There is no secret pipe hiding inside it. Nix resolves the inputs, calls a function with an attribute set, and keeps the attribute set that comes back. Which means publishing something new is just adding an attribute.
Publish the toolkit under packages.toolkit as well.
The real nixpkgs value is enormous rather than a short string, and it arrives
through that function in the same way this one does. Nothing about a
flake’s inputs is more magical than a named function argument.
Since outputs are just attributes, something can go and read them.
nix flake show does exactly that:
$ nix flake showgit+file:///home/yurii/my-program├───devShells│ └───x86_64-linux│ └───default: development environment└───packages └───x86_64-linux └───default: package 'my-program-1.0'
nix develop takes the default dev shell, nix build takes the default package.
The command and the output name are the two ends of one path across the
workbench.
Ask a project what it offers, without building any of it.
Handy on somebody else’s repository too. It tells you what there is to build before you go guessing at attribute names.
Official Nix still keeps flakes and the newer CLI behind the feature gate you turned on back in the CLI lesson. And now that you have seen what is behind it, that word on the label is worth a sentence.
“Experimental” means the interface can still change, which is a fair warning. It does not mean the community is sitting around waiting to find out, since an enormous number of projects already depend on flakes today.
- A common unpinned channel setup can move several independent Nix files at once.
flake.nixnames moving inputs and the outputs a project offers.flake.lockrecords the exact transitive input graph inside the project.- Locked input revisions determine the package versions the outputs produce.
outputsis an ordinary function, and conventional names connect its result to CLI tools.- The registry and a channel both live outside the project.
flake.nixandflake.locktravel with it. nix flake showreads a project’s outputs without building any of them.- Flakes are still experimental and widely adopted.


Share your thoughts