Nix 101 Course
From your first shell to writing production derivations, without cargo-culting.
Most Nix tutorials hand you a flake and hope. The 3 official manuals are complete but hard to learn from. This course bridges the gap in between: it builds your mental model from the ground up, so that new Nix errors stop being scary, new Nix tools feel familiar, and you can read and write real-world Nix with confidence.
Why this course is different
- Bottom-up, not copy-paste. We teach the sandbox, the derivation, the hash, and the store in that order, so the magic turns into mechanics you can reason about.
- Built on foundations that don't go stale. 99% of Nix works the same with and without flakes. We teach everything on the parts that haven't changed in ten years, then put flakes on top at the end. People from the NixOS Foundation endorse that order.
- Honest about trade-offs. Flakes get real coverage, including when not to use them.
- Patterns and anti-patterns from real organizations. We train hundreds of developers per year and have seen which patterns scale and which ones quietly grow into maintenance debt. You learn to tell them apart before committing either.
- Hands-on throughout. You'll write your first recursive functions, package GNU
hellowith patches you wrote yourself, build several variants of one package from a single recipe, and patch a whole dependency tree with one overlay.
What you'll learn
- Nix as a daily package manager and dev shell tool:
nix-shell,nix develop, and direnv - The Nix language: syntax, lazy evaluation, and the idioms you'll actually meet
- How a build really works: sandbox, derivation, hash, and store
- Writing derivations from
builtins.derivationup tostdenv.mkDerivation - Composing nixpkgs with
callPackage,override,overrideAttrs, and overlays - Flakes with their real advantages and costs, plus the
npins/nivalternatives - Debugging Nix: reading evaluation errors, tracing expressions, and dissecting failing builds
What you'll be able to do afterwards
- Ship a reproducible development environment your whole team uses from day one
- Package your own software and contribute fixes back to nixpkgs
- Know exactly how Nix code looks that maximizes reproducibility, caching, build speed, and composability
- Debug a Nix error calmly instead of rolling the dice on StackOverflow
- Judge Nix code no matter who wrote it: a colleague, a blog post, or an AI/LLM
- Move confidently into any advanced course (NixOS, Nix on Mac, ML/CUDA) without re-learning the basics
Who this is for
- Developers who need Nix for work soon and want to get up to speed without frustration
- Internal champions who are sold on Nix and now need the skills and arguments to convince their colleagues
- Decision makers who want a solid basis for a yes or no on Nix in their organization
- Current users who copy-paste expressions and want to actually understand them
No prior Nix and no functional programming background required. Everything works on Linux and macOS.
Prerequisites
Comfort in a Unix shell (bash or zsh), basic programming experience in any language, and a machine where you can install software. We cover the installation itself in the course.
What's included
Self-paced, hands-on lessons with lifetime access, including every future lesson and improvement, so the course doubles as your reference long after you finish. Several lessons are free to preview: start with Welcome: is this Nix training for you? and decide for yourself.
Lessons
Browse the videos included in this course.
Section 1 — Getting started: install Nix and score your first wins
7 lessonsGet Nix installed cleanly and feel the payoff within minutes: run any tool without installing it, keep the ones you want, reclaim disk space, and set up an editor that makes everything that follows go faster.
1.1 Welcome: is this Nix training for you? Free preview
You have run into Nix, followed a few tutorials, and watched the whole thing fall apart the moment you needed something the tutorial did not cover. This free opening video makes the case that Nix is worth the investment, then shows exactly how this…
1.2 Why Nix: the numbers that convince skeptical colleagues Free preview
Adopting Nix in a team is rarely blocked by technology. It's blocked by skeptical colleagues. This lesson hands you the neutral charts and numbers that answer the question "why Nix?", from the PhD thesis it started as to the large companies…
1.3 Installing Nix the right way: multi-user, flakes, and what to avoid
There are several ways to install Nix. The most obvious ones (your distro's package manager, Docker) work, but they quietly give you a worse experience for months. This lesson takes you from a clean Linux or macOS machine to a working Nix…
1.4 Your first Nix commands: nix run and nix shell
You just installed Nix, now what? This lesson shows the two commands that make Nix useful within minutes: nix run to launch any program from nixpkgs without installing it, and nix shell to open a temporary shell where the tool simply exists. Along…
1.5 Installing tools to keep with nix profile
A nix shell is gone the moment you close the terminal. When a tool should stay, like an editor or a language server, nix profile is how you install packages for your user with Nix. This lesson covers installing, listing, removing and upgrading…
1.6 Nix garbage collection: cleaning up the store
Everything Nix ever downloaded is still on your disk, which is why removed packages reappear instantly, and why /nix/store grows into many gigabytes. This lesson shows how Nix garbage collection works, why the first nix-collect-garbage run frees…
1.7 Nix editor setup: VS Code with nixd and nixfmt
The Nix language can feel strange at first, and reading it in a plain editor without any support makes that worse. Before the language lessons start, this video sets up Visual Studio Code for Nix: syntax highlighting, code completion, inline…
Section 2 — The Nix language
10 lessonsEvery Nix file you'll ever read or write is in this language. Learn it once, from syntax and the evaluation model to lazy evaluation and the everyday idioms, and the rest of the Nix world stops feeling like a foreign alphabet. Includes two hands-on exercises that make the syntax stick.
2.1 Why a config language has functions
Why does Nix use a purely functional language instead of YAML or JSON? This lesson answers the question every newcomer asks before starting a Nix language tutorial. Using a real Docker Compose file full of copy-pasted worker definitions, we show…
2.2 The Nix REPL as a power tool Free preview
The Nix REPL is the fastest way to test a Nix expression before it ends up buried in a thousand line file. This Nix REPL tutorial shows how to evaluate code interactively, read documentation without opening a browser, and inspect, build and even…
2.3 Nix syntax: the complete tour
One video, the whole Nix syntax. This Nix language tutorial covers attribute sets, functions, let and in blocks, string interpolation and imports, plus the constructs you should recognize but avoid. After it, real world Nix code stops looking…
2.4 Debugging Nix with trace and breakpoints
Sooner or later a value buried in nested let blocks is not what you expect, and you need a way to look inside. This lesson covers debugging Nix expressions with builtins.trace and the built-in breakpoint debugger, the two tools you will reach for…
2.5 Lazy evaluation explained: why 1/0 doesn't crash
x = 1 / 0, and evaluation succeeds? Lazy evaluation is the part of the Nix language that feels strangest to newcomers. It also explains 90% of the "wait, why didn't that fail?" moments you will ever have with Nix.
2.6 Lists and recursion in Nix
Nix has no for loops, so lists and recursion do the work that loops do elsewhere. This lesson shows how to take lists apart with head and tail, glue them back together with ++, and set up a recursive function in a language where every file is one…
2.7 Exercise: sum a list with recursion
Time to write your first recursive Nix function yourself. The task: a sum function that takes a list of numbers and returns their total. No loops, no mutation, just recursion. It sounds small, and that is the point: this is the pattern behind real…
2.8 Exercise: takeN and building lists recursively
The second exercise turns the difficulty up a notch. You write takeN, a function that returns the first n items of a list, which means consuming one list while building another at the same time. If it takes you more than ten minutes, that is normal…
2.9 Common idioms: map, filter, foldl' and friends
You could write every list operation recursively by hand, but you should not have to. This lesson introduces map, filter and foldl', the everyday idioms of functional programming in Nix, and shows where the huge nixpkgs standard library documents…
2.10 How to import nixpkgs, and what the empty braces mean
Almost every real Nix expression starts the same way: importing nixpkgs, the biggest package collection in the world. But why does import <nixpkgs> {} end in a pair of empty braces? This lesson answers that question, shows the different ways to get…
Section 3 — Dev shells: the productivity unlock
6 lessonsThis is the section that converts skeptics. By the end, your repos have a per-directory environment that activates automatically: the exact compiler, language version, and CLI tools your project needs, all without polluting your home directory.
3.1 Why dev shells beat system-wide installs and Docker
Setting up a project toolchain is often half a day of hunting dependencies out of a README, and one system update later it is broken again. This lesson compares the classic answers (installing everything system-wide with sudo, or building a Docker…
3.2 Your first dev shell with nix-shell Free preview
One file with a handful of lines, and your project carries its complete toolchain with it. No Docker image, no system-wide installs, no setup chapter in the README. We build a real dev shell for a real C project (tmux) on a machine that has no…
3.3 Deriving the dev shell from the package definition
Listing 15 packages in a shell.nix works, but it leaves you with two descriptions of your project: what developers use, and what CI and production actually build. This lesson flips the order. You describe the package build once, and Nix hands you…
3.4 An extended dev shell without duplication
Developers need more than the build does: language servers, linters, analyzers. But copying the package list into a second file means it goes stale. This lesson restructures the tmux project into a small release.nix layout where the package stays…
3.5 nix develop and flake-based dev shells
You have a working package and dev shell without flakes. This lesson turns the same tmux project into a flake.nix, so you see exactly what flakes add, what they cost in boilerplate, and when each style is the better fit. You end up entering the…
3.6 direnv: dev shells that load themselves
Typing nix-shell or nix develop in every project, every time, gets old fast. This lesson sets up direnv so the right development environment loads the moment you cd into a project folder and unloads when you leave. It works with flake and non-flake…
Section 4 — How Nix actually builds: sandbox → derivation → hash → store
6 lessonsEvery weird Nix error and every "why is it rebuilding the world?" question traces back to three things: the sandbox, the .drv, and the hash. Forty focused minutes here, and the rest of the course stops feeling like incantations. This is the section that turns Nix from magic into mechanics.
4.1 What actually happens when you run nix build
You type nix build and a store path falls out. This lesson opens up what happens in between: how a Nix expression turns into a derivation, and how a derivation turns into a path in the Nix store. That pipeline is the foundation of reproducible…
4.2 Inside the Nix build sandbox
Every Nix build runs in a sealed off mini world: no internet, no home folder, almost no files. In this lesson we break into that world and look around. Afterwards you know why "works on my machine" problems cannot happen with Nix.
4.3 The derivation is just a recipe
Every Nix build runs off a .drv file in the Nix store. In this lesson we create one with nix-instantiate, convert it to JSON, and read it line by line. It turns out a Nix derivation is a short, fully machine readable recipe, and the Nix build engine…
4.4 Exercise: package mini-hello with builtins.derivation
Time to build real software in the sandbox with your own hands. In this exercise you package mini-hello, a small C program with a Makefile, using nothing but builtins.derivation, gcc, GNU Make and coreutils. No mkDerivation, no helpers, no safety…
4.5 How Nix finds your runtime dependencies
Building mini-hello needed a compiler, GNU Make and coreutils. Running the finished binary needs almost none of that. This lesson shows how the Nix store keeps two different dependency trees for every package, build time and runtime, and how Nix…
4.6 Why Nix rebuilds your unchanged package
You run nix build on mini-hello twice in a row. Nothing changed, no file touched, and it compiles again anyway. This lesson finds the mistake in our own derivation that defeats the Nix cache, a mistake that shows up in real companies as whole teams…
Section 5 — Packaging real software with stdenv.mkDerivation
10 lessonsOnce you can write a mkDerivation, you can package literally anything: your company's internal tools, that one obscure CLI nobody has upstreamed, even your own scripts. By the end of this section you'll have packaged GNU hello end to end with patches you wrote yourself, and everything else in the Nix universe (buildPythonPackage, buildGoModule, buildRustPackage, crane) will read as sugar on top of what you just learned.
5.1 The build dance: from ./configure to your first mkDerivation
Almost every open source package installs the same way: download, unpack, ./configure, make, make install. In this lesson we build GNU hello by hand first, then let stdenv.mkDerivation do the whole ritual from a few lines of Nix. You see why the…
5.2 A minimal mkDerivation: build GNU hello yourself
Watching someone package software with Nix is one thing, typing the expression yourself is what makes it stick. In this short exercise you download the GNU hello tarball and write your own minimal stdenv.mkDerivation expression for it, this time…
5.3 What stdenv ships: default tools, buildInputs, and nativeBuildInputs
You never listed gcc, make, bash, or tar in your package, yet the build worked. This lesson shows what the Nix standard environment (stdenv) ships out of the box, and which mkDerivation parameters add the dependencies it does not include. You also…
5.4 Nix build phases: enable, disable, and override them
Every stdenv.mkDerivation build runs through fixed phases: unpack, patch, configure, build, check, install, fixup, and two more. This lesson maps out all nine Nix build phases, which seven matter, which two you can forget, and how each one can be…
5.5 Exercise: extend GNU hello
Time to get your hands dirty. In this exercise you rebuild GNU hello, but now you write the configure, build, check, and install phases yourself, then change the program's greeting with your own patch file. Things break in exactly the ways real…
5.6 Debugging failing Nix builds
A package compiles for an hour, fails, you change one line, and wait another hour for the next error. This lesson shows the debugging tools Nix gives you for failing builds: --keep-failed, --debug, the NIX_DEBUG variable, and a hook that lets you…
5.7 Pinning nixpkgs: the same build on every machine
Your mkDerivation call can be perfect and still build differently on every computer, because <nixpkgs> in angle brackets means some version of nixpkgs, not one specific version. This lesson shows how to pin nixpkgs to an exact commit so colleagues…
5.8 Fetching sources: fetchurl, fetchgit, and fixed-output derivations
Real projects depend on sources you don't host: upstream tarballs, GitHub repos, internal Git servers. This lesson shows how Nix downloads them reproducibly, and answers a question every newcomer asks: why do you start with a wrong hash on purpose?
5.9 Language-specific builders: Python, Go, and Rust with Nix
Nobody packages a Python, Go, or Rust project with raw mkDerivation. nixpkgs ships around 50 language specific builders for that, and they all follow one pattern. This lesson walks through buildPythonPackage, buildGoModule, and buildRustPackage so…
5.10 Build helpers: runCommand, writeShellApplication, and symlinkJoin
Sometimes a package is just one command that turns an input file into an output file, and writing full phase boilerplate for that would be silly. This lesson covers the nixpkgs build helpers worth using every week: runCommand, writeShellApplication…
Section 6 — Composing nixpkgs: callPackage, override, project layout
7 lessonsEverything in nixpkgs is a function of its inputs. This is where you stop forking nixpkgs to make changes and start composing your own variations cleanly: one derivation becomes the static build, the patched build, and the clang build without three copies of the recipe. It's also where you learn the repo layout your future colleagues will silently thank you for.
6.1 How to structure a real Nix project
One Nix expression is easy. A real Nix project has many: multiple subprojects, mixed languages, tests, docs, tooling. This lesson lays out the standard Nix project structure, what default.nix, shell.nix, release.nix and flake.nix are each for, and…
6.2 The callPackage pattern
The callPackage pattern looks like a useless indirection at first. Then you see what it enables and you never want to write a package any other way. In this lesson we turn a plain mkDerivation file into a package function, call it with…
6.3 How callPackage actually works
If callPackage felt like magic in the last lesson, this one takes the magic apart. We rebuild the mechanism in the Nix REPL with lib.callPackageWith and tiny toy functions, so you see exactly where the auto-filled arguments come from and where the…
6.4 override vs overrideAttrs
Both override and overrideAttrs change a package, so which one do you use when? This lesson draws the line precisely: one re-calls your package function with different arguments, the other changes what goes into mkDerivation itself. We prove the…
6.5 Exercise: a release.nix for GNU hello
Time to do it yourself. You take the GNU hello package from the earlier lessons, normalize its default.nix into a package function, and write a release.nix that exposes three variants: a plain default build, a build with a different compiler, and a…
6.6 Nix anti-patterns that bite you later
None of these Nix anti-patterns look wrong when you write them. They bite months later, in 500 line files, when nobody can tell where a variable comes from or why an overlay is silently ignored. This lesson collects the patterns we have seen cause…
6.7 Import from derivation (IFD) and why teams ban it
Import from derivation (IFD) is the anti-pattern people keep hearing about without knowing what it means. In this lesson we build the smallest possible IFD example: a Nix expression that generates another Nix expression, imports it, and builds it…
Section 7 — Advanced packaging topics
5 lessonsMost of the time mkDerivation is enough. These topics turn up when you cross into real-world projects: result symlinks bloating your source closure, executables that expect /usr/bin/env, binaries that need wrapping, builds that must cross-compile. Nothing here is essential for a first project; everything here will eventually bite you. Watch the ones that match your stack and skip the rest.
7.1 Source filtering with lib.fileset
Fixing a typo in a README should never cost you hours of recompilation, yet with src = ./. that is exactly what happens. This lesson covers source filtering in Nix with lib.fileset, lib.cleanSource, and cleanSourceWith, so only the files that…
7.2 makeWrapper: your own preconfigured version of any program
Some programs are almost right: they just need one extra flag, one environment variable, or one config file preloaded every single time. makeWrapper builds a small wrapper around any executable so it always starts exactly the way you want, without…
7.3 Dynamic patching with substituteInPlace
Third-party code often hard-codes paths like /usr/bin/... or bakes the build user and date into binaries, and both break builds in the Nix sandbox and hurt reproducibility. This lesson covers dynamic patching with substituteInPlace and its sibling…
7.4 patchShebangs: running scripts in the Nix sandbox
Your shell or Python script runs fine on your machine, then dies in the Nix build sandbox with "bad interpreter: No such file or directory". The reason: /usr/bin/env and /usr/bin/bash simply do not exist there. This lesson explains patchShebangs…
7.5 Nix cross-compilation with pkgsCross
Building ARM binaries on an Intel machine, Windows executables on Linux, static binaries with musl: Nix cross-compilation turns all of this into picking a different package set. This lesson shows pkgsCross and the crossSystem parameter, explains the…
Section 8 — Overlays: changes that propagate downstream
7 lessonsoverride patches one package. Overlays patch every package that depends on it, without forking nixpkgs. This is how teams maintain a single internal package set with one libc fix and 200 happily rebuilt dependents. It is also where most people first hit "infinite recursion", so we teach the why with diagrams instead of trial and error.
8.1 The problem nixpkgs overlays solve
You patched one package with override, but now you need that patch in every package that depends on it, directly and indirectly. This video shows why override and overrideAttrs cannot push a change down the dependency tree, and why nixpkgs overlays…
8.2 Overlay basics: your first overlay.nix
Your first working overlay: a small overlay.nix file that adds a package to nixpkgs so it looks and feels like it was always there. You learn the final: prev: function shape, how to pass overlays when importing nixpkgs, and a strong reason to define…
8.3 Surgical overrides: patch one package without rebuilding the world
A real overlay from a real project: rebuilding OpenCV with GTK window support for a computer vision setup in Python. There are two ways to do it, and they have very different costs. Replace opencv4 for every consumer and trigger a rebuild avalanche…
8.4 Fixpoint recursion: how overlays really work
lib.fix looks like the snake biting its own tail: a function applied to its own result. This lesson takes fixpoint recursion apart in the REPL and on the drawing board until nothing is left but pointers and thunks. It is the exact mechanism nixpkgs…
8.5 final vs prev: the two rule flavors
Both final and prev are versions of nixpkgs, so which one do you write in your overlay? Even experienced Nix people give contradicting answers in the forums, and there is a reason: two competing rule sets exist. This lesson shows where the two…
8.6 Composing overlays
Why would anyone pass a list of 15 overlays to nixpkgs? Because overlays compose. This short lesson shows how separate overlays for production packages and debug instrumentation combine into a testing overlay, and how a whole list of overlays…
8.7 Exercise: patching across the dependency tree
The favorite exercise of the whole course, and the one where overlays usually click. You get a miniature repository: a small app that prints ABCD through a multi-level tree of four C++ libraries, and your job is to make it print XYZW. Every trick…
Section 9 — Flakes
10 lessonsFlakes are everywhere, and everywhere controversial. This section gives you an honest picture: what flakes actually solve, how to read and write them fluently, and where they cost you. Afterwards you can use them when they help and refuse them when they don't, in both cases for reasons you can defend in code review.
9.1 What flakes are and why they exist
Nix flakes are the most argued about feature in the ecosystem, and this lesson opens the flakes section with the question forum threads never answer: what problem do flakes actually solve? You learn where evaluation caching, the flake registry…
9.2 Anatomy of a flake: inputs, outputs and the lock file
Every flake.nix file has the same skeleton: a description, flake inputs, and outputs. This lesson takes a minimal flake apart line by line, so flake.lock, legacyPackages and the packages.system.name attribute path stop being mysterious. Along the…
9.3 How to enable flakes
Flakes are still an experimental feature, so a fresh Nix install refuses every nix flake command until you switch them on. This short lesson shows the exact configuration line for plain Nix and the snippet for NixOS. The whole process takes about a…
9.4 Starting a flake from scratch with nix flake init
Time to write your own flake. Starting in an empty folder, nix flake init generates a template, and this lesson explains every line of it, then grows it into something real: your own patched package, a dev shell for nix develop, and static and cross…
9.5 Flake inputs in depth: follows, flake = false and lock file size
Flake inputs look simple until your flake.lock starts pulling in the dependencies of your dependencies. In this lesson we measure what each input really costs on a real project, then take control with the follows mechanism and flake = false. You…
9.6 Flake outputs in depth: packages, apps, checks and more
Packages and dev shells are only two of the output categories a flake can provide. This lesson walks through the whole set: apps, checks, overlays, nixosModules, nixosConfigurations and formatter, each connected to the command that consumes it. One…
9.7 Exercise: flakify a real project
Now it is your turn. You get a project you already know from the overlays section, complete with release.nix, shell.nix and an overlay file, and the task is to flakify it: same packages, same dev shell, now served through a flake.nix. This is where…
9.8 Real life flakes: how experienced users structure them
How do experienced Nix users actually structure their flakes? This lesson reads real repositories: tazjin's Nixery with a flakified build layered on top, and a Rust CLI built with naersk, direnv, treefmt and a full checks setup. You see the…
9.9 Anti-patterns: why you do not need flake-utils or flake-parts
Almost every flakes tutorial reaches for flake-utils or flake-parts to handle multiple architectures. This lesson makes the case that you usually need neither, and shows live how removing them leaves your flake.nix shorter, supporting more…
9.10 When to flake, and when not to
The final lesson of the flakes section answers the question everything has been building toward: when are flakes the right tool, and when do they get in your way? Drawn from real customer projects, you get the honest trade-offs: evaluation caching…
Instant access
Start watching the moment your purchase completes.
Lifetime access
Buy once and revisit every lesson whenever you need it.
Secure checkout
Payments handled by Paddle, our trusted reseller.
Taught by Nixcademy
The same material we teach in our professional, instructor-led Nix and NixOS classes — built from real training experience helping engineers and teams adopt Nix in production.
What learners say
“I recently had the opportunity to participate in nixcademy's Nix & NixOS training, and it was truly transformative for our team. The trainer's knowledge and ability to simplify complex concepts made the learning experience seamless. The week-long training, although challenging, has had a strong enabling effect on our daily work results.”
“Jacek's invaluable support and expertise were instrumental in enabling my team to develop customized systems for sensor data collection. His adept use of Nix for ensuring maintainability and quick deployments has been nothing short of remarkable. My employees have consistently praised his exceptional teaching style.”
“Jacek's technical expertise and dynamic teaching style have been a game-changer for my team as we navigate the fast-paced world of AI and mobile app development. His exceptional support has been an incredible asset, and I cannot imagine going back to our previous ways of working without him.”