curl -L https://nixos.org/nix/install | sh
nix --version
In a Nix shell environment, you can immediately use any program packaged with Nix, without installing it permanently.
nix-shell -p cowsay lolcat
cowsay Hello, Nix! | lolcat
Running programs once, You can go even faster, by running any program directly:
~/Documents/sonu/nixos » nix-shell -p cowsay --run "cowsay Nix" sonaojus@Mac01
_____
< Nix >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
If you need an additional program temporarily, you can run a nested Nix shell. The programs provided by the specified packages will be added to the current environment.
These shell environments are very convenient, but the examples so far are not reproducible yet. Running these commands on another machine may fetch different versions of packages, depending on when Nix was installed there.
What do we mean by reproducible? A fully reproducible example would give exactly the same results no matter when or where you run the command. The environment provided would be identical each
nix-shell -p git --run "git --version" --pure -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/2a601aafdc5605a5133a2ca506a34a3a73377247.tar.gz
If you’re done trying out Nix for now, you may want to free up some disk space occupied by the different versions of programs you downloaded by running the examples:
nix-collect-garbage
#!/usr/bin/env nix-shell
#! nix-shell -i bash --pure
#! nix-shell -p bash cacert curl jq python3Packages.xmljson
#! nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/2a601aafdc5605a5133a2ca506a34a3a73377247.tar.gz
curl https://github.com/NixOS/nixpkgs/releases.atom | xml2json | jq .
The key point is that all the #! lines are processed by nix-shell before executing the script itself. The -I option sets the NIX_PATH before the environment is built, ensuring that the correct version of nixpkgs is used when resolving the packages listed with -p.
So, when nix-shell reads the script, it:
Sets the NIX_PATH with the -I option. Fetches and evaluates the packages listed with -p from the specified nixpkgs archive URL. Starts a bash shell in a pure environment with the specified packages available.
let
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05";
pkgs = import nixpkgs { config = {}; overlays = []; };
in
pkgs.mkShellNoCC {
packages = with pkgs; [
cowsay
lolcat
];
}
You may want to run some commands before entering the shell environment. These commands can be placed in the shellHook attribute provided to mkShellNoCC.
Set shellHook to output a colorful greeting:
let
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05";
pkgs = import nixpkgs { config = {}; overlays = []; };
in
pkgs.mkShellNoCC {
packages = with pkgs; [
cowsay
lolcat
];
GREETING = "Hello, Nix!";
shellHook = ''
echo $GREETING | cowsay | lolcat
'';
}
```s
{ pkgs ? import <nixpkgs> {} }:
nix-shell
Use nix-instantiate --eval to evaluate the expression in a Nix file.
echo 1 + 2 > file.nix nix-instantiate --eval file.nix 3
Attribute sets and let expressions are used to assign names to values. Assignments are denoted by a single equal sign (=).
Whenever you encounter an equal sign (=) in Nix language code:
On its left is the assigned name.
On its right is the value, delimited by a semicolon (;).
Attribute set { ... } An attribute set is a collection of name-value-pairs, where names must be unique.
The following example shows all primitive data types, lists, and attribute sets.
Also known as “let expression” or “let binding”
let expressions allow assigning names to values for repeated use.
let
b = a + 1;
a = 1;
in
a + b
with ...; ... The with expression allows access to attributes without repeatedly referencing their attribute set.
Example:
let
a = {
x = 1;
y = 2;
z = 3;
};
in
with a; [ x y z ]
[ 1 2 3 ] The expression
with a; [ x y z ] is equivalent to
[ a.x a.y a.z ]
inherit is shorthand for assigning the value of a name from an existing scope to the same name in a nested scope. It is for convenience to avoid repeating the same name multiple times.
Previously known as “antiquotation”.
The value of a Nix expression can be inserted into a character string with the dollar-sign and braces (${ }).
Example:
let
name = "Nix";
in
"hello ${name}"
Also known as “angle bracket syntax”.
Example:
/nix/var/nix/profiles/per-user/root/channels/nixpkgs The value of a lookup path is a file system path that depends on the value of builtins.nixPath.In practice, points to the file system path of some revision of Nixpkgs.
For example, <nixpkgs/lib> points to the subdirectory lib of that file system path:
<nixpkgs/lib> /nix/var/nix/profiles/per-user/root/channels/nixpkgs/lib
let
f = x: x + 1;
a = 1;
in [ f a ]
Also known as “curried functions”.
Nix functions take exactly one argument. Multiple arguments can be handled by nesting functions.
Such a nested function can be used like a function that takes multiple arguments, but offers additional flexibility.
So far we have only covered what we call pure expressions: declaring data and transforming it with functions.
In practice, describing derivations requires observing the outside world.
There is only one impurity in the Nix language that is relevant here: reading files from the file system as build inputs
Build inputs are files that derivations refer to in order to describe how to derive new files. When run, a derivation will only have access to explicitly declared build inputs.
The only way to specify build inputs in the Nix language is explicitly with:
- File system paths
- Dedicated functions.
Nix and the Nix language refer to files by their content hash. If file contents are not known in advance, it’s unavoidable to read files during expression evaluation.
Whenever a file system path is used in string interpolation, the contents of that file are copied to a special location in the file system, the Nix store, as a side effect.
The evaluated string then contains the Nix store path assigned to that file.
Example:
echo 123 > data
"${./data}"
"/nix/store/h1qj5h5n05b5dl5q4nldrqq8mdg7dhqk-data"
Files to be used as build inputs do not have to come from the file system.
The Nix language provides built-in impure functions to fetch files over the network during evaluation:
builtins.fetchurl
builtins.fetchTarball
builtins.fetchGit
builtins.fetchClosure
These functions evaluate to a file system path in the Nix store.
Example:
builtins.fetchurl "https://github.com/NixOS/nix/archive/7c3ab5751568a0bc63430b33a5169c5e4784a0ff.tar.gz"
"/nix/store/7dhgs330clj36384akg86140fqkgh8zf-7c3ab5751568a0bc63430b33a5169c5e4784a0ff.tar.gz"
Some of them add extra convenience, such as automatically unpacking archives.
Example:
builtins.fetchTarball "https://github.com/NixOS/nix/archive/7c3ab5751568a0bc63430b33a5169c5e4784a0ff.tar.gz"
"/nix/store/d59llm96vgis5fy231x6m7nrijs0ww36-source"