Skip to content

Nix

Nix is a combination of the Nix Language, the Nix Package Manager and the Nix Operating System.

It essentially revolves around functions that have the following format:

    {What is the current state of the world} :

    {
         What is the changed state of the world
    }
Or put another way, takes arguments and returns a list of dictionaries.
    { pkgs, lib, ... }:

    {
            option1.enable = true;
            systemPackages = with pkgs; [
                neovim
            ];
    }

NixOS

    sudo /etc/nixos/configuration.nix
    sudo nixos-rebuild switch

All packages, previous generations etc are stored in the nix store ls /nix/store and can be cleaned up with sudo nixos-collect-garbage --delete-older-than 15d
The rebuild command does not update packages and you are pinned to a channel (upstream, stable, unstable) from the github repo for NixOS that is specified in the configuration.nix file.

Flakes

Flakes are basically instructions that take some inputs and produce some outputs. They consist of a flake.nix file and a flake.lock file that has the pinned versions of the files.
They are not changed until nix update flake is run in the flake directory.
The NixOS can be represented by a flake, which means it can be backed up to GitHub, cloned, run and your OS is back in action.
Flake directory can be modular. If a directory is imported in a nix file, it will automatically source default.nix, which itself can import other .nix files.
The most important thing is to make sure the NixOS Configurations name is called with .#configurationName.
This way of course you can have multiple configurations.
When calling nixOS rebuilds you need to specify .#hostname or .#username if they don't match your system.
With my flake.nix and flake.lock files in a directory, and a configuration.nix file with a host called default, I can rebuild my entire system with: sudo nixos-rebuild switch --flake /directory/with/flake.#default

Nix Language

Dynamic, lazy evaluated, functional language.
Derivations: Precise descriptions of how contents of existing files are used to derive new files.
Everything is an nix expression that when evaluated will return a nix value.
nix-shell looks for shell.nix file by default in current directory to create the shell environment.
nix repl for a language environment
nix-instantiate --eval looks for default.nix if no file name is specified.

Basics

Attribute sets and let .. in bindings can have names and return values.
. notation is used to access values from the sets.

    {
    string = "hello";
    integer = 1;
    float = 3.141;
    bool = true;
    null = null;
    list = [ 1 "two" false ];
    attribute-set = {
        a = "hello";
        b = 2;
        c = 2.718;
        d = false;
        }; # comments are supported
     }
Wherever you find a colon : in Nix language code:
On its left is the function argument
On its right is the function body
Function arguments are the third way, apart from attribute sets and let expressions, to assign names to values. Notably, values are not known in advance: the names are placeholders that are filled when calling a function.
An attribute set argument can be given a name to be accessible as a whole using the @ syntax.
import takes a path to a Nix file, reads it to evaluate the contained Nix expression, and returns the resulting value. If the path points to a directory, the file default.nix in that directory is used instead.
Since a Nix file can contain any Nix expression, imported functions can be applied to arguments immediately. That is, whenever you find additional tokens after a call to import, the value it returns should be a function, and anything that follows are arguments to that function.
    { pkgs, lib, ... }:
    # ... multiple uses of `pkgs`
    # ... multiple uses of `lib`
Sometimes both pkgs and lib are passed as arguments. In that case, one can assume pkgs.lib and lib to be equivalent. This is done to improve readability by avoiding repeated use of pkgs.lib.

Vimjoyer video