Skip to main content
czerasz.com: notes
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Nix

Install

sh <(curl -L https://nixos.org/nix/install) --daemon

Configuration

mkdir -p ~/.config/nix/
cat <<EOS > ~/.config/nix/nix.conf
extra-experimental-features = flakes nix-command
auto-optimise-store = false
EOS

Profile

Alternative to nix-env. Nix profiles are versioned, allowing them to be rolled back easily.

nix profile install nixpkgs#cowsay

List installed packages

nix profile list

Flake

What is a Flake?

  • a Flake is a git repo with a flake.nix file inside
  • Flakes can dependencies on other Flakes
  • dependencies are recorded in a lock file

List content of the flake:

nix flake show nixpkgs

List available templates:

nix flake show templates

Create a flake from a specific template:

nix flake init --template templates#simpleContainer

or

nix flake init -t github:czerasz/nix-flake-sample-template

other options:

View flake metadata:

$ nix flake metadata github:nixos/nixpkgs/nixos-unstable
Resolved URL:  github:nixos/nixpkgs/nixos-unstable
Locked URL:    github:nixos/nixpkgs/f5892ddac112a1e9b3612c39af1b72987ee5783a
Description:   A collection of packages for the Nix package manager
Path:          /nix/store/r88zkfh22shcgj0c4zh9jj2q5r1z9wjn-source
Revision:      f5892ddac112a1e9b3612c39af1b72987ee5783a
Last modified: 2023-09-29 20:25:13

View current flake metadata:

nix flake metadata .

Update only specific input:

nix flake lock --update-input nixpkgs

Update lock file and commit at once:

nix flake update --commit-lock-file

Run development shell:

nix develop --command "${SHELL}"

Examples

Rust example (flake.nix):

{
  description = "A flake for learning Rust";

  inputs = {
    nixpkgs = {
      url = "github:nixos/nixpkgs/nixos-23.05";
    };
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
  };
  inputs.flake-utils.url = "github:numtide/flake-utils";

  outputs = { self, nixpkgs, flake-utils, ... }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = self.legacyPackages.${system};
        # pkgs = import nixpkgs {
        #   inherit system;
        #   config = {
        #     allowUnfree = true;
        #   };
        # };
      in
      {
        devShells.default =
          pkgs.mkShell {
            buildInputs = [
              pkgs.rustup
            ];

            shellHook = ''
              echo 'Welcome to learning Rust'
            '';
          };
      }
    );
}

Script example (flake.nix):

# resource: https://github.com/vimjoyer/nix-update-input/blob/main/flake.nix
{
  description = "hello";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
  };

  outputs = { nixpkgs, ... }:
    let
      forAllSystems = function:
        nixpkgs.lib.genAttrs [
          "x86_64-linux" # 64-bit Intel/AMD Linux
          "aarch64-linux" # 64-bit ARM Linux
          "x86_64-darwin" # 64-bit Intel macOS
          "aarch64-darwin" # 64-bit ARM macOS
        ]
          (system: function nixpkgs.legacyPackages.${system});
    in
    {
      packages = forAllSystems (pkgs: {
        default = pkgs.writeShellScriptBin "hello" ''
          echo '{"hello": "world"}' \
          | ${pkgs.jq}/bin/jq "."
        '';
      });
    };
}

Python:

# resource: https://github.com/kemalmao19/devShell/blob/main/python/python311/flake.nix
devShells = forAllSystems ({ pkgs }: {
  default = let
    # Use Python 3.11
    python = pkgs.python311;

  in pkgs.mkShell {
    # The Nix packages provided in the environment
    packages = [
      # Python plus helper tools
      (python.withPackages (ps:
        with ps; [
          pandas
          numpy
          ...

          # Formatting
          black
        ]))
    ];
  };
});

Terraform from releases:

# flake.nix
{
  description = "Terraform flake";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs";
  };

  outputs = { self, nixpkgs, ... }@inputs:
    let
      system = "x86_64-linux";
      pkgs = nixpkgs.legacyPackages.${system};
      version = "1.6.5";
      src = pkgs.fetchzip {
        # curlOpts = ["-L"];
        curlOpts = "-L";
        url = "https://releases.hashicorp.com/terraform/${version}/terraform_${version}_linux_amd64.zip";
        # cat tf.zip | openssl dgst -sha256 -binary | openssl base64 -A
        sha256 = "sha256-K8JZogX/+Nw6dmMnGhjagMc/4riIBCHmmEwtJieabH0=";
        # sha256 = pkgs.lib.fakeSha256;
      };
    in
    {
      packages.${system}.default = pkgs.stdenv.mkDerivation {
        name = "terraform";
        src = src;
        system = system;
        # buildPhase = "ls -al > hello";
        installPhase = "mkdir -p $out/bin; install -t $out/bin terraform";
      };
    };
}

Platform specific:

buildInputs = [
  # Linux build inputs
] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [
  # additional darwin specific inputs
  pkgs.libiconv
];

Generate flake.nix based on existing project:

nix run "https://flakehub.com/f/DeterminateSystems/fh/0.1.5.tar.gz" -- init

View the Nix expression of a Nix package:

nix edit nixpkgs#bat

View package attributes:

nix eval nixpkgs#terraform --apply builtins.attrNames

Nix Language

  • Evaluate basic Nix expression:

    {
      x = [ "y" ];
      y = 1;
      z = 1 + 1;
    }
    EOS
    
    nix eval -f example.nix x
    
  • let ... in syntax:

    let
      h = "Hello";
      w = "World";
      n = 2
    in
    {
      hi = h + " " + w;
      ho = "${h} Ho"
      hn = "${h} ${toString n} You"
    }
    
    nix eval -f example.nix hi
    
  • functions and conditionals:

    let
      min = x : y : if (x < y) then x else y;
      max = x : y : if (x > y) then x else y;
    in
    {
      low = min 5 3;
      high = max 9 4;
    }
    
    nix eval -f example.nix low
    
  • useful variables:

    • builtins.currentSystem

      Example x86_64-linux

  • basic usage with flake.nix:

    {
      outputs = { self }: {
        foo = "bar";
      };
    }
    
    $ nix eval .#foo
    "bar"
    
  • additional attributes

    inputs@{a, b, ...}: is equivalent to {a, b, ...}@inputs:

    Use inputs anywhere in the flake:

    outputs = { nixpkgs, ... }@inputs:
      let
        ...
      in
      {
        ...
        buildInputs = [
          inputs.nixpkgs-stable.legacyPackages.${system}.python36
        ];
      };
    
  • function example:

    let
      pkgs = { system ? builtins.currentSystem }:
        import <nixpkgs> { inherit system; };
      fn = { pkgs, myList }: pkgs.lib.reverseList myList;
    in
    rec {
      reverse = fn { pkgs = pkgs { }; myList = [ 1 2 3 4 ]; };
      result = "${toString reverse}";
    }
    

    or self evaluating:

    let
      pkgs = ({ system ? builtins.currentSystem }:
        import <nixpkgs> { inherit system; }) { };
      fn = { pkgs, myList }: pkgs.lib.reverseList myList;
    in
    rec {
      reverse = fn { pkgs = pkgs; myList = [ 1 2 3 4 ]; };
      result = "${toString reverse}";
    }
    
    nix eval -f example.nix result
    
  • with syntax:

    use

    buildInputs = with pkgs; [
      rustup
    ];
    

    instead of

    buildInputs = [
      pkgs.rustup
    ];
    
  • inherit:

    {input ? "default"}:
    let
      some_value = "some value: ${input}";
      list = [1 2 3];
    in
    {
      inherit input some_value list;
      # the same as
      # input = input;
      # some_value = some_value;
      # list = list;
    }
    
  • concat lists:

    {}:
    let
      list_one = [1 2 3];
      list_two = [4 5 6];
    in
    {
      concat_list = list_one ++ list_two;
    }
    
  • importing:

    list.nix:

    [1 2 3]
    
    {
      imported_list = import './list.nix';
    }
    

Usage

  • run arbitrary command

    echo '{"hello": "world"}' | nix run nixpkgs#jq .
    
  • search package:

    nix search nixpkgs cargo
    

    nixpkgs is shorthand for github:NixOS/nixpkgs

  • without configuration file

    nix shell nixpkgs#youtube-dl
    

    or

    nix-shell --pure -p nix -p vim -p stdenv
    

    or

    nix-shell --pure -p nix vim stdenv
    

    or

    nix-shell --pure --packages nix vim stdenv
    
  • reproducible

    nix-shell -p git \
      --pure \
      --run "git --version" \
      -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/2a601aafdc5605a5133a2ca506a34a3a73377247.tar.gz
    

    where

    -I determines what to use as a source of package declarations

  • use shebang

    #!/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 .
    
  • free up disk space

    nix-collect-garbage
    

    additionally delete old generations older than 30 days:

    nix-collect-garbage --delete-older-than 30d
    
  • get fresh package versions

    nix-channel --update
    

    Then one can rebuild installed derivations

    nix-env -u
    
  • with configuration file

    Sample configuration file (shell.nix):

    with (import <nixpkgs> { });
    mkShell {
      buildInputs = [
        pkgs.rustup
      ];
    
      shellHook = ''
        echo 'welcome to development environment'
      '';
    }
    
    nix-shell --pure shell.nix
    
  • install software globally

    nix-env -i python3
    

    better way (less memory usage):

    nix-env -iA nixpkgs.bat
    
  • uninstall software globally

    nix-env -e python3
    
  • list generations

    nix-env --list-generations --profile /nix/var/nix/profiles/system
    
  • list channels

    nix-channel list
    

Utilities

Fix formatting:

nix run nixpkgs#nixpkgs-fmt -- .

Check formatting:

nix run nixpkgs#nixpkgs-fmt -- --check .

or with building (slower)

nix run github:nix-community/nixpkgs-fmt -- --check .

Generate dependency closure:

nix-store --query --graph $(nix-build --no-out-link -A inputDerivation basic-shell.nix)

Verify that Flake configuration is fine:

nix flake check

Free up disk space:

nix store gc --verbose

Debugging

Interactive shell - discover functions:

git clone --depth 1 https://github.com/NixOS/nixpkgs.git
cd nixpkgs
# type :? for help
nix repl .

Interactive shell for debugging:

nix repl -f function.nix

Interactive shell with nixpkgs:

nix eval -I nixpkgs=channel:nixos-21.05 --show-trace /test.nix

Find setup script path:

nix derivation show 'nixpkgs.stdenv' | grep 'setup.sh'

Build dependency graph:

nix-store --query --graph /nix/store/mspb2bklaqssjwpmcicwvsmqrh1ffb96-vim-9.0.1897 | dot -Tsvg > vim.svg

Resources