Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Classic Nix commands: nix-env, nix-build, nix-shell, nix-channel

By updated

Improve this page

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-build and nix-shell (the two most useful ones still today)
  • Understand why nix-env is incompatible with nix profile
  • Manage channels with nix-channel and 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 -p or nix-build,
  • maintaining a project that uses a shell.nix or default.nix,
  • debugging an installation on a machine configured with the old channels,
  • gradually migrating a workflow based on nix-env to nix 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.

Terminal window
nix-build '<nixpkgs>' -A hello
Result
/nix/store/5z2yp3ysx8476c8g5w25b0smlgkjvaq3-hello-2.12.3
Terminal window
./result/bin/hello
Result
Hello, 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.

Aspectnix-buildnix build
Source syntax'<nixpkgs>' -A hellonixpkgs#hello
ResolutionChannels (NIX_PATH)Flake registries
OutputStore path on stdoutresult link (silent)
PinningManual (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.

Terminal window
nix-shell -p cowsay --run 'cowsay "classic nix-shell"'
Result
___________________
< classic nix-shell >
-------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||

Combine several packages

Several packages are chained after a single -p, separated by spaces and without repeating the option.

Terminal window
nix-shell -p curl jq --run 'echo "curl and jq available"'
Result
curl and jq available

With 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.

shell.nix
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
buildInputs = [
pkgs.python3
pkgs.curl
pkgs.jq
];
}
Terminal window
nix-shell
# → interactive shell with python3, curl and jq

Differences 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.

Aspectnix-shell -p pkgnix shell nixpkgs#pkg
ResolutionChannels (NIX_PATH)Flake registry
EnvironmentAdds the full stdenvAdds only the package
Project fileshell.nixflake.nix → devShells
Aspectnix-shell (file)nix develop
Fileshell.nixflake.nix
PinningManualAutomatic flake.lock
ReproducibilityDepends on NIX_PATHGuaranteed 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.

Terminal window
# Search for a package
nix-env -qaP '.*htop.*'
# Install
nix-env -iA nixpkgs.htop
# List installed packages
nix-env -q
# Remove
nix-env -e htop
# Upgrade everything
nix-env -u
# Rollback
nix-env --rollback
# List the generations
nix-env --list-generations

Why 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.

  1. Incompatible with nix profile, the two profile formats are mutually exclusive.
  2. No pinning, the installed version depends on the state of the channel at installation time.
  3. Resolution by name, nix-env -i htop may install an unexpected package if several match.
  4. 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-envnix profile
nix-env -qaP patternnix search nixpkgs pattern
nix-env -iA nixpkgs.pkgnix profile add nixpkgs#pkg
nix-env -qnix profile list
nix-env -e pkgnix profile remove pkg
nix-env -unix profile upgrade --all
nix-env --rollbacknix profile rollback
nix-env --list-generationsnix 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.

Terminal window
# List the configured channels
nix-channel --list
# Add a channel
nix-channel --add https://channels.nixos.org/nixpkgs-unstable nixpkgs
# Update
nix-channel --update

Channels 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.

AspectChannelsFlakes
LockingNo (rolling)Yes (flake.lock)
ReproducibilityDepends on the momentGuaranteed by the hash
ConfigurationGlobal (~/.nix-channels)Per project (flake.nix)
Resolution<nixpkgs> through NIX_PATHnixpkgs 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.

Terminal window
nix-instantiate '<nixpkgs>' -A hello
Result
warning: you did not specify '--add-root'; the result might be removed by the garbage collector
/nix/store/cnraiw0hbdl6jzdhbkn8dah2hqj7xgij-hello-2.12.3.drv

Modern 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.

Terminal window
# Delete unreferenced packages
nix-collect-garbage
# Also delete the old generations older than 30 days
nix-collect-garbage -d --delete-older-than 30d

Modern 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.

Terminal window
# Show the dependencies of a path
nix-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 store
nix-store --verify --check-contents

Complete 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.

ClassicModernUsage
nix-env -qaPnix searchSearch
nix-env -iAnix profile addInstall
nix-env -enix profile removeRemove
nix-env -unix profile upgrade --allUpgrade
nix-env --rollbacknix profile rollbackRollback
nix-buildnix buildBuild
nix-shell -pnix shellTemporary shell
nix-shell (file)nix developDevelopment env.
nix-channelFlake registriesPackage sources
nix-instantiatenix eval --raw …drvPath, nix derivation showInspect the derivation
nix-collect-garbagenix store gcGarbage collection
nix-store -qnix path-infoStore info

Key points

  • nix-build and nix-shell still work and are useful for projects that use default.nix or shell.nix.
  • nix-env and nix profile are mutually incompatible, if you use the modern commands, do not use nix-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 -p brings in the full stdenv, which is heavier than nix 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

6 questions
6 min
70% to pass

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

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn