No description
Find a file
2026-07-09 17:47:25 -06:00
README.md flow 2026-07-09 17:47:25 -06:00

What Is Nix?

"Nix" usually refers to three related things.

  • The Language
  • The Package Manager
  • The Operating System

Diagram showing Nix as three pillars: the language, the package manager, and NixOS

Source: https://old.reddit.com/r/NixOS/comments/rffnx8/who_says_the_naming_is_confusing/

The Language

A declarative, functional language used to describe:

  • software
  • dependencies
  • build steps
  • system configuration

Instead of writing a sequence of setup commands, you describe the result you want.

That makes the configuration easier to reason about, easier to share, and easier to rebuild later.

The Package Manager

A cross-platform package manager that runs on Linux and macOS.

It:

  • reads .nix files
  • fetches source code
  • builds software in isolation
  • stores the results in /nix/store

Quick example:

{ pkgs }:

pkgs.buildGoModule {
  pname = "my-app";
  version = "1.0.0";

  src = pkgs.fetchFromGitHub {
    owner = "geoff";
    repo = "hello-world";
    rev = "v1.0.0";
    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
  };

  vendorHash = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
}

This says: fetch a specific version of a Go app from GitHub, build it in isolation, and put the result in /nix/store.

More on /nix/store later.

Here, hash locks the app source, and vendorHash locks the Go dependencies, so Nix can rebuild the same result reliably.

stdenv.mkDerivation is the low-level building block Nix uses to build and install software. buildGoModule is a higher-level helper built on top of it for Go projects.

Example:

{ pkgs }:

pkgs.stdenv.mkDerivation {
  pname = "hello-curl";
  version = "1.0.0";

  src = pkgs.fetchFromGitHub {
    owner = "geoff";
    repo = "hello-curl";
    rev = "v1.0.0";
    hash = "sha256-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=";
  };

  buildInputs = [ pkgs.curl ];

  buildPhase = ''
    cc main.c -o hello-curl -lcurl
  '';

  installPhase = ''
    mkdir -p $out/bin
    cp hello-curl $out/bin/
  '';
}

This says: fetch the app source, build it against curl, and install the final binary into the package output.

Imagine main.c uses libcurl to make an HTTP request. The Nix expression declares that dependency explicitly instead of assuming curl is already available somewhere on the system.

The Operating System

NixOS is a Linux distribution built around the Nix package manager.

You describe your system in configuration files instead of manually setting it up piece by piece.

That includes things like:

  • installed packages
  • users
  • system services
  • networking
  • boot settings
  • desktop configuration

NixOS applies the same idea not just to apps, but also to configuration like sshd_config.

In other words, NixOS takes the same ideas used for packages and applies them to the whole machine.

Quick example:

{ pkgs, ... }:

{
  environment.systemPackages = with pkgs; [
    git
    firefox
  ];

  services.openssh.enable = true;

  users.users.geoff = {
    isNormalUser = true;
    extraGroups = [ "wheel" ];
  };
}

This says: install git and firefox, enable the SSH service, and create a user named geoff.

Key trait:

Each rebuild creates a new "generation". If an upgrade breaks something, you can roll back to an older generation.

Because of that, whole system configurations are:

  • reproducible
  • isolated
  • rollback-friendly

How Nix Works

Reference: https://nixos.org/guides/how-nix-works/

Nix stores everything in /nix/store using unique hash-based paths.

Example:

/nix/store/5rnfzla9kcx4mj5zdc7nlnv8na1najvg-firefox-3.5.4

Format: /nix/store/[HASH]-[PACKAGE]-[VERSION]

The hash is based on the build inputs, so if the inputs change, the output path changes too.

That means:

  • if an input changes, Nix builds a new version instead of overwriting the old one
  • multiple versions of the same package can coexist
  • builds are reproducible
  • upgrades are safer

Packages are also built in isolation, which helps prevent them from accidentally depending on random software already installed on the machine.

For example, one Python app might need Python 3.10 and an older dependency set, while another needs Python 3.12 and newer packages. On a traditional system, global Python packages can clash. In Nix, each environment can carry its own Python version and dependencies.

Important Differences

Traditional Linux usually installs and updates software in place.

NixOS describes the system you want, then builds a new version of that system.

Traditional Linux systems put software in shared paths like /bin, /usr, and /lib.

NixOS does not place software in those traditional global paths.

That means NixOS does not use the traditional Filesystem Hierarchy Standard (FHS) layout for software packages.

Instead, software lives in /nix/store, and many system files are generated and symlinked from there.

This is a big reason NixOS can support safe rollbacks and multiple versions at once.

It also means some software needs extra work because it assumes a traditional FHS-style layout with paths like /usr/bin or /lib.

Why I Think This Is Cool

What I like about NixOS is that it makes my machine declarative and reproducible.

Instead of relying on a long list of manual steps, I can describe the machine directly in configuration.

That means:

  • I know what is installed
  • I know how the host is configured
  • I can share that configuration with other people
  • I can reuse it on another machine
  • I am less likely to completely break a host when changing it

For me, the biggest appeal is reliability. The system feels easier to rebuild, easier to understand, and easier to trust.

Tradeoffs

  • the Nix language has a learning curve
  • the filesystem layout is not traditional
  • some software expects traditional Linux paths and needs adaptation

Takeaway

Nix turns system setup into something declarative, reproducible, and reversible.

Instead of mutating your machine in place, it builds a new version of it.