Think about the last time you wanted to try some command line tool somebody recommended. You installed it. And then, in all likelihood, you never removed it again, because uninstalling things is a chore nobody has ever enjoyed doing.
That is not carelessness, it is just how package managers work. Before you can use a thing, you have to change your machine:
$ sudo apt install helloSetting up hello...
Nix can do something else entirely. It can lend you a package for exactly one command, or exactly one shell, and then take it back. It may fetch a store path along the way, but it does not add the program to a global package list and it does not leave a profile entry behind.
One small thing to get out of the way first. The newer nix command and flakes
are still officially gated behind an experimental flag. Most installers turn them
on for you already, but if Nix ever complains, NixOS can keep the setting in the
machine configuration:
Turn on the newer command interface and flakes.
- Include
"nix-command"and"flakes"
And yes, “experimental” is exactly the sort of word that should make a beginner nervous. The interface really can still change. But this is what everybody uses every day, and starting with the old commands instead would only mean learning the same thing twice.
Every modern Nix command needs to know two things: where to get the software, and
which piece of that source you actually want. So they all take the same shape,
source#attribute.
$ nix shell nixpkgs#helloHere nixpkgs is the source and hello is the package attribute, the same
attribute you’d select from pkgs. The registry works out that nixpkgs means a
nixpkgs snapshot, which is all you need for a quick experiment.
Time to actually borrow something. nix shell opens a shell whose PATH
includes the package you asked for, and changes nothing else about your system.
$ nix shell nixpkgs#hello$ helloHello, world!$ exit$ hellobash: hello: command not found
Then you leave, and it’s gone. The package may stay in the Nix store for next time, but your shell has stopped carrying the key to it.
Open a temporary shell containing ripgrep.
Which makes this the nicest way there is to try a tool out before deciding whether it deserves a place in your system, your home, or a particular project.
Sometimes even a shell is more than you wanted. nix run is smaller still: fetch
the selected app, run it, and hand you back your terminal.
Run hello once without staying inside a shell.
Use nix shell when you want tools around you. Use nix run when the program is
the whole job.
Both of those commands assume you already know the attribute to ask for. So what do you do when you don’t?
Humans say “a terminal multiplexer.” Nix needs an exact package attribute.
So nix search takes the source, then as many words as you like, and matches
them against every package’s name and description.
Search nixpkgs for a terminal multiplexer, describing it rather than naming it.
The attributes you were after are zellij and tmux. Search the descriptions
first, then take the candidate for a spin in a temporary shell.
Hold on, though. If nothing was installed, where is the program actually coming from?
Nix never copied it into /usr/bin. It put the package’s store path on PATH
for the temporary environment and left everything else alone:
$ nix shell nixpkgs#hello$ which hello/nix/store/w2q5r...-hello-2.12.2/bin/hello
That prefix is derived from the package’s build inputs, which is why two different versions get two different paths and can sit side by side without ever overwriting each other.
There is one catch to all this convenience, and it’s the one from the last
lesson wearing a new hat. nixpkgs#hello asks the registry what nixpkgs means
right now, and right now keeps changing.
Choose the address tied to one exact source revision.
Which does not mean you should start typing revisions by hand, because nobody sane works that way. It means the pinning has to live somewhere, and a flake lockfile is where it goes: written down once, in the repository, and remembered for you. I swear we will get back to this later :D
- Modern commands use
source#attributeto identify what they should use. nix shelllends tools to a temporary shell.nix runruns one selected app and returns.nix search nixpkgs wordsfinds attributes from human descriptions.- Temporary environments change
PATH, not/usr/binor a global package list.


Share your thoughts