The nix-env, nix-build, nix-shell and nix-channel commands make
up the historical interface of Nix. They are gradually being replaced by the
modern commands
(nix search, nix shell, nix run, nix profile…), but you will still meet
them in many tutorials, wikis and existing scripts. This guide presents
them with their modern equivalent so that you can read and adapt legacy
code. The outputs were captured on Nix 2.35.2.
What you will learn
- Identify the classic commands and understand their role
- Use
nix-buildandnix-shell(the two most useful ones still today) - Understand why
nix-envis incompatible withnix profile - Manage channels with
nix-channeland understand the move to flakes - Translate each classic command into its modern equivalent
In what context?
You will come across the classic commands in several situations:
- reading a tutorial or a README that uses
nix-shell -pornix-build, - maintaining a project that uses a
shell.nixordefault.nix, - debugging an installation on a machine configured with the old channels,
- gradually migrating a workflow based on
nix-envtonix profile.
nix-build, build a package
nix-build is the predecessor of nix build. It evaluates a Nix
expression, builds the result and creates in the current directory a symbolic
link named result that points to the store path. This link also serves as a
garbage collection root: as long as it exists, the result will not be
deleted by nix-collect-garbage.
nix-build '<nixpkgs>' -A hello/nix/store/5z2yp3ysx8476c8g5w25b0smlgkjvaq3-hello-2.12.3./result/bin/helloHello, world!Differences with nix build
Both commands produce the same derivation, but they do not resolve the
source in the same place and do not return the result the same way:
nix-build prints the store path on standard output, which lets a script
capture it, whereas nix build simply creates the result link.
| Aspect | nix-build | nix build |
|---|---|---|
| Source syntax | '<nixpkgs>' -A hello | nixpkgs#hello |
| Resolution | Channels (NIX_PATH) | Flake registries |
| Output | Store path on stdout | result link (silent) |
| Pinning | Manual (no lock) | Automatic flake.lock |
nix-shell, a shell with dependencies
nix-shell creates a temporary shell environment in which the requested
packages are present in the PATH, without installing anything into the
profile. It is the common predecessor of nix shell and nix develop,
which explains why a single classic command covers two modern commands today.
Quick use with -p
The -p option builds a throwaway environment containing the named
packages, and --run runs a command in it then hands control back instead
of opening an interactive shell. Nothing is installed in the profile: on exit,
only the content downloaded into the store remains.
nix-shell -p cowsay --run 'cowsay "classic nix-shell"' ___________________< classic nix-shell > ------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||Combine several packages
Several packages are chained after a single -p, separated by spaces and
without repeating the option.
nix-shell -p curl jq --run 'echo "curl and jq available"'curl and jq availableWith a shell.nix file
The most common use of nix-shell is with a shell.nix file at the root of
a project: run with no argument, nix-shell looks for this file in the
current directory and builds the environment it describes.
{ pkgs ? import <nixpkgs> {} }:pkgs.mkShell { buildInputs = [ pkgs.python3 pkgs.curl pkgs.jq ];}nix-shell# → interactive shell with python3, curl and jqDifferences with the modern commands
nix-shell covers two uses that the modern commands split into two distinct
tools. The first table compares the throwaway use on the command line,
the second the development environment described by a file versioned with
the project.
| Aspect | nix-shell -p pkg | nix shell nixpkgs#pkg |
|---|---|---|
| Resolution | Channels (NIX_PATH) | Flake registry |
| Environment | Adds the full stdenv | Adds only the package |
| Project file | shell.nix | flake.nix → devShells |
| Aspect | nix-shell (file) | nix develop |
|---|---|---|
| File | shell.nix | flake.nix |
| Pinning | Manual | Automatic flake.lock |
| Reproducibility | Depends on NIX_PATH | Guaranteed by the lock |
nix-env, manage the packages of the profile
nix-env is the predecessor of nix profile. It lets you search,
install, list and remove packages in the user profile, that is the set of
symbolic links that makes a program available in the PATH without going
through a temporary shell. It is the only classic command whose migration is
blocking: a profile created by nix profile is permanently closed to it.
Main commands
These options fit in one letter and combine: -q queries, -i
installs, -e erases, and -A designates the package by its
attribute path (nixpkgs.htop) rather than by its displayed name.
# Search for a packagenix-env -qaP '.*htop.*'
# Installnix-env -iA nixpkgs.htop
# List installed packagesnix-env -q
# Removenix-env -e htop
# Upgrade everythingnix-env -u
# Rollbacknix-env --rollback
# List the generationsnix-env --list-generationsWhy avoid nix-env
On a fresh workstation, the question hardly arises: nix-env keeps a
global, unversioned state, whereas the whole point of Nix lies in
reproducibility. The four limits below are paid for when you try to
replay an installation on another machine.
- Incompatible with
nix profile, the two profile formats are mutually exclusive. - No pinning, the installed version depends on the state of the channel at installation time.
- Resolution by name,
nix-env -i htopmay install an unexpected package if several match. - No flake.lock, impossible to reproduce exactly the same environment.
Correspondence table
Each row reads as a direct translation: the command on the left and the one on the right produce the same functional effect. They simply do not apply to the same profile format, so migration happens in one go, not command by command.
nix-env | nix profile |
|---|---|
nix-env -qaP pattern | nix search nixpkgs pattern |
nix-env -iA nixpkgs.pkg | nix profile add nixpkgs#pkg |
nix-env -q | nix profile list |
nix-env -e pkg | nix profile remove pkg |
nix-env -u | nix profile upgrade --all |
nix-env --rollback | nix profile rollback |
nix-env --list-generations | nix profile history |
nix-channel, manage package sources
Channels are the old mechanism to resolve <nixpkgs> to a specific version
of the nixpkgs tree. Each account keeps its own list in ~/.nix-channels
(root's in /root/.nix-channels), and the downloaded trees live under
/nix/var/nix/profiles/per-user/<account>/channels. In multi-user mode, the
default NIX_PATH looks at root's channels first, which explains why
sudo nix-channel --list may show something different from the same command
without sudo.
Main commands
A channel is declared once, then refreshed on demand: --update
downloads the new description of the nixpkgs tree and points <nixpkgs> to it.
Every classic command run afterwards therefore resolves different
versions, without any file of your project changing.
# List the configured channelsnix-channel --list
# Add a channelnix-channel --add https://channels.nixos.org/nixpkgs-unstable nixpkgs
# Updatenix-channel --updateChannels vs flakes
The difference comes down to one point: a channel is a moving cursor shared
by the whole machine, a flake freezes the version in a flake.lock file
specific to the project. Two colleagues who updated their channel on different
dates will not get the same packages; with a committed lock, they get the same
hash.
| Aspect | Channels | Flakes |
|---|---|---|
| Locking | No (rolling) | Yes (flake.lock) |
| Reproducibility | Depends on the moment | Guaranteed by the hash |
| Configuration | Global (~/.nix-channels) | Per project (flake.nix) |
| Resolution | <nixpkgs> through NIX_PATH | nixpkgs through the registry |
Other classic commands
The three commands below have no urgent migration: they serve diagnostics
and cleaning up the store, not daily package management. You will mostly
come across them in maintenance scripts and in forum answers about a
/nix/store that is overflowing.
nix-instantiate, evaluate a derivation
nix-instantiate stops at evaluation: it writes the .drv file, the build
recipe, into the store and prints its path, without compiling or downloading
the package itself. The warning before it reminds you that this .drv is
protected by no GC root.
nix-instantiate '<nixpkgs>' -A hellowarning: you did not specify '--add-root'; the result might be removed by the garbage collector/nix/store/cnraiw0hbdl6jzdhbkn8dah2hqj7xgij-hello-2.12.3.drvModern equivalent: nix eval --raw nixpkgs#hello.drvPath to get the same path,
nix derivation show nixpkgs#hello to read the recipe.
nix-collect-garbage, free space
With no option, the command only deletes the store paths that no root
references any more. The -d option goes further and destroys the old
generations of the profiles, which makes rollback impossible to the
versions concerned; --delete-older-than 30d limits the damage to those older
than thirty days.
# Delete unreferenced packagesnix-collect-garbage
# Also delete the old generations older than 30 daysnix-collect-garbage -d --delete-older-than 30dModern equivalent: nix profile wipe-history + nix store gc
nix-store, operations on the store
nix-store -q queries the dependency graph in both directions:
--references lists what a path depends on, --referrers lists what depends
on it, its referrers. This second direction answers the question that
blocks a deletion, when the garbage collector refuses to free a path still
in use.
# Show the dependencies of a pathnix-store -q --references /nix/store/vli6...-ripgrep-15.2.0
# Show the referrers (what depends on this path)nix-store -q --referrers /nix/store/vli6...-ripgrep-15.2.0
# Check the integrity of the storenix-store --verify --check-contentsComplete correspondence table
Keep this table at hand when you read an old tutorial: it gives the
modern equivalent of every classic command. Beware, the equivalence is
about usage, not argument syntax, and certainly not state: moving from
nix-env to nix profile requires reinstalling the packages, the two
profiles cannot read each other.
| Classic | Modern | Usage |
|---|---|---|
nix-env -qaP | nix search | Search |
nix-env -iA | nix profile add | Install |
nix-env -e | nix profile remove | Remove |
nix-env -u | nix profile upgrade --all | Upgrade |
nix-env --rollback | nix profile rollback | Rollback |
nix-build | nix build | Build |
nix-shell -p | nix shell | Temporary shell |
nix-shell (file) | nix develop | Development env. |
nix-channel | Flake registries | Package sources |
nix-instantiate | nix eval --raw …drvPath, nix derivation show | Inspect the derivation |
nix-collect-garbage | nix store gc | Garbage collection |
nix-store -q | nix path-info | Store info |
Key points
nix-buildandnix-shellstill work and are useful for projects that usedefault.nixorshell.nix.nix-envandnix profileare mutually incompatible, if you use the modern commands, do not usenix-env.- Channels are replaced by flake registries, which offer automatic locking through
flake.lock. - For a new project, prefer the modern commands and flakes, the classic commands are mainly useful to understand legacy code.
nix-shell -pbrings in the full stdenv, which is heavier thannix shell, which only adds the requested package.
Knowledge check
Check that the essentials of this guide are acquired. The questions only cover what has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: The Nix language: types, functions, attrsets and expressions
A new full quiz with random questions
Work again only on the questions you missed