nix
This notes assume to have the experimental-features = nix-command flakes
enabled.
nix.conf (ref)
nix config show
# experimental-features
# enable additional experimental features
# flake-registery
# url of global registry
# tarball-ttl
# time the downloaded tarball is treated as valid
nix search (ref)
nix search <installable> <regex>
nix search nixpkgs glibc
nix profile (ref)
The history allows to install packages, update them and easily rollback.
# Install/remove/upgrade package(s) (creates a new history version).
nix profile install <installable>
nix profile remove
nix profile upgrade --all
# List installed packages.
nix profile list
# Show different hisitory versions.
nix profile history
# Rollback profile history.
nix profile rollback [--to N]
nix store (ref)
# Show all alive store paths (paths with active reference).
nix-store --gc --print-live
# Show all dead store paths (paths w/o active reference).
nix-store --gc --print-dead
# Run garbage collection on nix store. This deletes all paths which are no
# gcroots and any dependency of any gcroot.
nix store gc
# Delete single path from store.
nix store delete <path>
# gcroots are for example created automatically when installing packages into
# the profile or when building a flake locally.
# gcroots are located under /nix/var/nix/gcroots
#
# One can also create mamual gcroots (eg for tmp operation).
> nix-store --gc --print-dead | grep 'binutils-2.44$'
/nix/store/wcv8n2k53w8sbffpf716gxj6mjb5jf26-binutils-2.44
> mkdir -p /nix/var/nix/gcroots/tmp
> ln -s /nix/store/wcv8n2k53w8sbffpf716gxj6mjb5jf26-binutils-2.44 /nix/var/nix/gcroots/tmp/keep-binutils
> nix-store --gc --print-dead | grep 'binutils-2.44$'
> nix-store --gc --print-live | grep 'binutils-2.44$'
/nix/store/wcv8n2k53w8sbffpf716gxj6mjb5jf26-binutils-2.44
nix flake (ref)
Flakes provide a description for reproducible builds.
# Create a new flake in a folder with name.
nix flake new <name>
# Create a new flake from given template.
nix flake new -t <template> <name>
# Create a new flake with the c-hello output from the templates flake.
nix flake create -t templates#c-hello myflake
# Show the outputs of a flake
nix flake show <flake>
# Show outputs from the default "templates" flake.
nix flake show templates
# Assumes '.' as flake (which effectively means flake.nix in cwd).
nix flake show
# Show the derivation of an installable in pretty format.
nix derivation show <installable>
# Show the derivation of the glibc output from the nixpkg flake.
nix derivation show nixpkgs#glibc
# Assumes '.' as flake.
nix derivation show
# Show a flakes metadata (eg store path, inputs, description, ..)
nix flake metadata <flake>
# Update the versions in the flake.lock file.
nix flake update
Use
nix registry list
to list available global flakes.Documentation for installable syntax.
a bare bones flake
The following shows a bare bones flake using the
builtins.derivation
function to define an output called
moose. The builtin provides an empty environment.
In general, a derivation is a declarative description of how to run an executable (builder) on a set of inputs (input derivations aka dependencies) to produce a set of outputs (store paths).
# The flake is effectively an attribute set with a standard set of attributes.
{
description = "bare bones (flake)";
# Input(s) of the flake.
# Each input attribute is passed into the output function below.
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
# The 'outputs' attribute is a function, accepting an attribute set with a
# self reference and all the inputs specified above.
# The function shall return an attribute set with different outputs.
# There are standardized outputs for different commands such as:
# > nix build
# > nix develop
outputs = { self, nixpkgs }: let
# Define local variables with let .. in construct.
system = "x86_64-linux";
# Import another flake, passing an attribute set.
# inherit system, is effectively system = system;
pkgs = import nixpkgs { inherit system; };
in
# Return attribute set.
{
# Some output.
moose = builtins.derivation {
# -- Required attributes.
inherit system;
name = "bone";
builder = "${pkgs.bash}/bin/bash";
# -- Optional attributes.
args = [ "-c" "echo hello > $out" ];
};
};
}
Understanding this example is crucial as any abstractions such as the
nixpkgs.stdenv
builds on top of this.
One can inspect and build the derivation as follows.
# Show the derivation for the output "moose".
> nix derivation show .#moose
{
"/nix/store/q2l7g7myy5gmks7jml6hz2jd73yybplq-bone.drv": {
...
"inputDrvs": {
"/nix/store/d2gv7y7i7bw79dpfskzzk2g4h6mc0677-bash-interactive-5.2p37.drv": {
}
# Build the output 'moose' for the flake.nix in the cwd ('.').
> nix build .#moose ; cat result
hello
.#moose
references the flake.nix in the cwd'.'
and the outputmoose
.
An interesting point to observe is that nix computed bash as input derivation (inputDrv) and hence as input dependency for this output.
a stdenv flake
The stdenv
library from the nixpkgs flake provides the
mkDerivation
function to simplify building packages (defining derivations).
Many tools commonly used to build software are available out of the box.
Specifying build and runtime dependencies can also be done easiy.
The default builder provided by the mkDerivation
function, organizes the build
into multiple phases like config, build and install. When defining the
derivation these phases can be easily overwritten.
The example show a simple build and installation of a C file.
{
description = "stdenv (flake)";
inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; };
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = nixpkgs.legacyPackages.${system};
in {
# Enable support for 'nix fmt'.
formatter.${system} = pkgs.nixfmt;
# This is the default output that will be build & run if no output is
# specified, when running the following in the flakes directory.
# > nix build
# > nix run
packages.${system}.default = pkgs.stdenv.mkDerivation {
# Either specify 'name' or 'pname & version'.
# In the latter case, 'name' will be ${pname}-${version}.
pname = "test";
version = "0.1";
# There are different builtins to also unpack or fetch tarballs.
src = ./src;
# The default builder of the stdenv defines many different phases that
# can be overwritten.
buildPhase = ''
gcc -O2 -g -o test test.c
'';
installPhase = ''
mkdir -p $out/bin
cp test $out/bin
'';
};
};
}
One can also define multiple output directories using the outputs
attribute
in the derivation. Each output turns into an environment variable of the same
name. Use nix derivation show
to inspect the outputs and the environment the
builder inherits.
The for example the glibc package in the nixpkgs flake, which provides multiple outputs.
> nix derivation show nixpkgs#glibc
..
"outputs": {
..
"out": {
"path": "/nix/store/g3s0z9r7m1lsfxdk8bj88nw8k8q3dmmg-glibc-2.40-66"
},
"static": {
"path": "/nix/store/lfj0w1r0ppj2swb11pz8vkppmsy1rf6y-glibc-2.40-66-static"
}stdenv/flake.nix
},
..
a development shell flake
The nixpkgs
flake also provides the mkShell
derivation
function (specialization of mkDerivation
), which can be used to easily define
a development environment.
The examples shows an environment with the zig
compiler and zls
, the zig lsp
server. Running nix develop
will drop in a shell where these packages are
available.
{
description = "dev shell (flake)";
inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; };
outputs = { self, nixpkgs }:
let
system = "x86_64-linux";
pkgs = import nixpkgs { inherit system; };
in {
devShells.${system}.default = pkgs.mkShell {
buildInputs = [
pkgs.zig
pkgs.zls
];
};
};
}
nix lang basics
Nix is a functional language, where everything is an expression. The following shows enough nix lang to come quite far.
$ nix repl
nix-repl> 1 + 2
3
# String interpolation.
# (Assignment operation special to repl).
nix-repl> foo = "bar"
nix-repl> "hello ${foo}"
"hello bar"
# Simple function with argument.
nix-repl> f = a: a + 2
nix-repl> f 4
6
# Attribute sets (kv).
nix-repl> { a = 1; b = 2; }
{
a = 1;
b = 2;
}
# Function taking an attribute set.
nix-repl> f = { a, b }: a + b
nix-repl> f { a = 1; b = 2; }
3
# Defining local variables with "let .. in".
nix-repl> let x = 1; in x + 3
4
nix-repl> x
error: undefined variable 'x'
# Let .. in expression returning an attribute set (handy when defining derivations).
nix-repl> let x = "abc"; in { name = "bar ${x}"; }
{ name = "bar abc"; }
# Show all builtin functions.
nix-repl> builtins
{
abort = «primop abort»;
add = «primop add»;
..