WIP
This commit is contained in:
parent
35402cccda
commit
d2814acdc9
@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
description = "A minimal dev shell — your first flake";
|
description = "A minimal dev shell: your first flake";
|
||||||
|
|
||||||
# Inputs: other flakes this one depends on.
|
# Inputs: other flakes this one depends on.
|
||||||
# `nixpkgs` is the big package set. `follows` isn't used here, but you'll
|
# `nixpkgs` is the main package set. `follows` isn't used here, but you'll
|
||||||
# see it a lot when composing flakes (e.g. `inputs.foo.inputs.nixpkgs.follows = "nixpkgs";`).
|
# see it a lot when composing flakes (e.g. `inputs.foo.inputs.nixpkgs.follows = "nixpkgs";`).
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
|||||||
@ -1,52 +1,52 @@
|
|||||||
# Glossary
|
# Glossary
|
||||||
|
|
||||||
Core vocabulary you'll hit in the first hour of Nix. Skim, don't memorize — come back as needed.
|
Core vocabulary you'll hit in the first hour of Nix. Skim, don't memorize; come back as needed.
|
||||||
|
|
||||||
## The store and builds
|
## The Store and Builds
|
||||||
|
|
||||||
- **Nix store** — `/nix/store`. Immutable, content-addressed directory where *everything* Nix builds lives. Each entry is prefixed by a hash of its inputs.
|
- **Nix store**: `/nix/store`. Immutable, content-addressed directory where *everything* Nix builds lives. Each entry is prefixed by a hash of its inputs.
|
||||||
- **Store path** — a single entry under `/nix/store`, e.g. `/nix/store/abc123…-hello-2.12.1`. The hash makes it unique per set of build inputs.
|
- **Store path**: a single entry under `/nix/store`, e.g. `/nix/store/abc123…-hello-2.12.1`. The hash makes it unique per set of build inputs.
|
||||||
- **Derivation (`.drv`)** — a *recipe* for a build: inputs, builder script, env vars, outputs. Produced by evaluating Nix code. Not the built artifact itself.
|
- **Derivation (`.drv`)**: a *recipe* for a build, covering inputs, builder script, env vars, and outputs. Produced by evaluating Nix code. Not the built artifact itself.
|
||||||
- **Realisation / "realising a derivation"** — actually executing the `.drv` to produce the output store path(s). "Build" colloquially means this.
|
- **Realisation / "realising a derivation"**: actually executing the `.drv` to produce the output store path(s). "Build" colloquially means this.
|
||||||
- **Output path** — the store path a derivation produces. A derivation can have multiple outputs (e.g. `out`, `dev`, `man`, `lib`).
|
- **Output path**: the store path a derivation produces. A derivation can have multiple outputs (e.g. `out`, `dev`, `man`, `lib`).
|
||||||
- **Closure** — a store path plus all its runtime dependencies, transitively. What you need to copy to another machine to actually use something.
|
- **Closure**: a store path plus all its runtime dependencies, transitively. What you need to copy to another machine to actually use something.
|
||||||
- **Hash** — content/input hash that names store paths. Changing any input changes the hash, which changes the path — this is how Nix guarantees no cache collisions.
|
- **Hash**: content/input hash that names store paths. Changing any input changes the hash, which changes the path; this is how Nix guarantees no cache collisions.
|
||||||
- **Fixed-output derivation (FOD)** — a derivation whose output hash you declare up front (e.g. source tarballs, `fetchurl`). Allowed network access during build; everything else is sandboxed offline.
|
- **Fixed-output derivation (FOD)**: a derivation whose output hash you declare up front (e.g. source tarballs, `fetchurl`). Allowed network access during build; everything else is sandboxed offline.
|
||||||
|
|
||||||
## Language
|
## Language
|
||||||
|
|
||||||
- **Nix (the language)** — lazy, purely functional, dynamically typed. Every `.nix` file is one expression.
|
- **Nix (the language)**: lazy, purely functional, dynamically typed. Every `.nix` file is one expression.
|
||||||
- **Attrset** — `{ a = 1; b = "x"; }`. The main data structure.
|
- **Attrset**: `{ a = 1; b = "x"; }`. The main data structure.
|
||||||
- **Lambda** — `x: x + 1` or `{ a, b }: a + b`. Functions take one argument; multi-arg functions are attrset-destructured.
|
- **Lambda**: `x: x + 1` or `{ a, b }: a + b`. Functions take one argument; multi-arg functions are attrset-destructured.
|
||||||
- **`let ... in`** — local bindings: `let x = 1; in x + 1`.
|
- **`let ... in`**: local bindings, for example `let x = 1; in x + 1`.
|
||||||
- **`with expr; body`** — brings `expr`'s attrs into scope for `body`. Common in `with pkgs; [ hello jq ]`. Useful but can shadow bindings — use sparingly.
|
- **`with expr; body`**: brings `expr`'s attrs into scope for `body`. Common in `with pkgs; [ hello jq ]`. Useful but can shadow bindings, so use sparingly.
|
||||||
- **`inherit`** — shorthand to pull names from outer scope into an attrset: `{ inherit pkgs system; }` ≡ `{ pkgs = pkgs; system = system; }`.
|
- **`inherit`**: shorthand to pull names from outer scope into an attrset: `{ inherit pkgs system; }` ≡ `{ pkgs = pkgs; system = system; }`.
|
||||||
- **`import`** — evaluate another `.nix` file. `import ./foo.nix { }` imports and calls it.
|
- **`import`**: evaluate another `.nix` file. `import ./foo.nix { }` imports and calls it.
|
||||||
- **`callPackage`** — a nixpkgs convention that auto-supplies function arguments from a package set. You'll see it everywhere in nixpkgs.
|
- **`callPackage`**: a nixpkgs convention that auto-supplies function arguments from a package set. You'll see it everywhere in nixpkgs.
|
||||||
|
|
||||||
## Package management
|
## Package Management
|
||||||
|
|
||||||
- **nixpkgs** — the big community-maintained collection of Nix expressions for ~100k packages. Lives at `github:NixOS/nixpkgs`.
|
- **nixpkgs**: the community-maintained collection of Nix expressions for ~100k packages. Lives at `github:NixOS/nixpkgs`.
|
||||||
- **Channel** — a named, periodically-updated snapshot of nixpkgs (e.g. `nixos-unstable`, `nixos-25.11`). Pre-flakes way to pin. Flakes mostly replace this with lockfiles.
|
- **Channel**: a named, periodically-updated snapshot of nixpkgs (e.g. `nixos-unstable`, `nixos-25.11`). Pre-flakes way to pin. Flakes mostly replace this with lockfiles.
|
||||||
- **Overlay** — a function that extends/overrides a package set. Lets you patch, pin, or add packages without forking nixpkgs.
|
- **Overlay**: a function that extends or overrides a package set. Lets you patch, pin, or add packages without forking nixpkgs.
|
||||||
- **Profile** — a symlink tree representing "what's installed" for a user or system. `nix-env`, `nix profile`, NixOS, and home-manager all manage profiles.
|
- **Profile**: a symlink tree representing "what's installed" for a user or system. `nix-env`, `nix profile`, NixOS, and home-manager all manage profiles.
|
||||||
- **Generation** — a versioned snapshot of a profile. Every change creates a new generation; old ones stay until garbage-collected. This is how rollback works.
|
- **Generation**: a versioned snapshot of a profile. Every change creates a new generation; old ones stay until garbage-collected. This is how rollback works.
|
||||||
- **Garbage collection (`nix-collect-garbage`)** — deletes store paths not reachable from any "GC root" (profiles, running processes, `result` symlinks).
|
- **Garbage collection (`nix-collect-garbage`)**: deletes store paths not reachable from any "GC root" (profiles, running processes, and `result` symlinks).
|
||||||
|
|
||||||
## Flakes
|
## Flakes
|
||||||
|
|
||||||
- **Flake** — a directory with a `flake.nix`. Has pinned `inputs` and structured `outputs`. Reproducible, composable, schema-driven.
|
- **Flake**: a directory with a `flake.nix`. Has pinned `inputs` and structured `outputs`. Reproducible, composable, and schema-driven.
|
||||||
- **`flake.lock`** — JSON file pinning the exact revision (and hash) of each input. Commit it.
|
- **`flake.lock`**: JSON file pinning the exact revision (and hash) of each input. Commit it.
|
||||||
- **Flake reference** — URL-like string identifying a flake: `github:NixOS/nixpkgs`, `path:./foo`, `git+https://…`, `nixpkgs` (registry alias).
|
- **Flake reference**: URL-like string identifying a flake: `github:NixOS/nixpkgs`, `path:./foo`, `git+https://…`, or `nixpkgs` (registry alias).
|
||||||
- **Registry** — short-name → flake-ref mapping. `nixpkgs` resolves via the global registry by default.
|
- **Registry**: short-name to flake-ref mapping. `nixpkgs` resolves via the global registry by default.
|
||||||
- **Pure evaluation** — flakes evaluate in a sandbox: no env vars, no arbitrary filesystem reads, only declared inputs. This is what makes them reproducible.
|
- **Pure evaluation**: flakes evaluate in a sandbox with no env vars, no arbitrary filesystem reads, and only declared inputs. This is what makes them reproducible.
|
||||||
|
|
||||||
## NixOS & home-manager
|
## NixOS and home-manager
|
||||||
|
|
||||||
- **NixOS module** — a function `{ config, lib, pkgs, ... }: { options = …; config = …; }`. The unit of NixOS configuration.
|
- **NixOS module**: a function `{ config, lib, pkgs, ... }: { options = …; config = …; }`. The unit of NixOS configuration.
|
||||||
- **home-manager** — user-level declarative config (dotfiles, per-user packages, services). Works standalone or as a NixOS module.
|
- **home-manager**: user-level declarative config for dotfiles, per-user packages, and services. Works standalone or as a NixOS module.
|
||||||
|
|
||||||
## CLI: old vs. new
|
## CLI: Old vs. New
|
||||||
|
|
||||||
| Old (pre-flakes) | New (flakes) |
|
| Old (pre-flakes) | New (flakes) |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
|||||||
@ -9,9 +9,9 @@ Confusingly, both are called "Nix." Separate them in your head and everything ge
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. The mental model: eval, then build
|
## 1. The Mental Model: Eval, Then Build
|
||||||
|
|
||||||
Every `nix build` / `nix develop` runs in two phases:
|
Every `nix build` or `nix develop` runs in two phases:
|
||||||
|
|
||||||
```
|
```
|
||||||
.nix source ──(evaluate)──▶ .drv file ──(realise)──▶ /nix/store/...-output
|
.nix source ──(evaluate)──▶ .drv file ──(realise)──▶ /nix/store/...-output
|
||||||
@ -23,13 +23,13 @@ Every `nix build` / `nix develop` runs in two phases:
|
|||||||
- **Evaluation** runs the Nix language. Pure, in-memory, fast. Produces `.drv` files.
|
- **Evaluation** runs the Nix language. Pure, in-memory, fast. Produces `.drv` files.
|
||||||
- **Realisation** actually builds things. Sandboxed. Slow. Outputs go to `/nix/store`.
|
- **Realisation** actually builds things. Sandboxed. Slow. Outputs go to `/nix/store`.
|
||||||
|
|
||||||
You can evaluate without building (`nix eval`, `nix-instantiate`) and you can build without touching the language if you already have a `.drv`. Most errors you'll see are *eval* errors — typos in attrsets, missing arguments, undefined names.
|
You can evaluate without building (`nix eval`, `nix-instantiate`) and you can build without touching the language if you already have a `.drv`. Most errors you'll see are *eval* errors: typos in attrsets, missing arguments, and undefined names.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. The language in 5 minutes
|
## 2. The Language in 5 Minutes
|
||||||
|
|
||||||
### Primitives and collections
|
### Primitives and Collections
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
42 # integer
|
42 # integer
|
||||||
@ -40,7 +40,7 @@ You can evaluate without building (`nix eval`, `nix-instantiate`) and you can bu
|
|||||||
true false null
|
true false null
|
||||||
[ 1 2 3 ] # list (space-separated, NOT comma)
|
[ 1 2 3 ] # list (space-separated, NOT comma)
|
||||||
{ a = 1; b = "two"; } # attrset
|
{ a = 1; b = "two"; } # attrset
|
||||||
/foo/bar # path (literal — not a string!)
|
/foo/bar # path (literal, not a string!)
|
||||||
./relative/path # path relative to current file
|
./relative/path # path relative to current file
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ The `...` means "ignore extra attrs." Without it, passing extras is an error.
|
|||||||
```nix
|
```nix
|
||||||
let
|
let
|
||||||
x = 1;
|
x = 1;
|
||||||
y = x + 1; # can reference earlier bindings (and each other — lazy)
|
y = x + 1; # can reference earlier bindings (and each other: lazy)
|
||||||
in x + y
|
in x + y
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ in x + y
|
|||||||
{ inherit (pkgs) hello jq; } # pulls hello/jq from pkgs into this attrset
|
{ inherit (pkgs) hello jq; } # pulls hello/jq from pkgs into this attrset
|
||||||
```
|
```
|
||||||
|
|
||||||
### `with` (use cautiously)
|
### `with` (Use Cautiously)
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
with pkgs; [ hello jq ripgrep ]
|
with pkgs; [ hello jq ripgrep ]
|
||||||
@ -86,11 +86,11 @@ with pkgs; [ hello jq ripgrep ]
|
|||||||
[ pkgs.hello pkgs.jq pkgs.ripgrep ]
|
[ pkgs.hello pkgs.jq pkgs.ripgrep ]
|
||||||
```
|
```
|
||||||
|
|
||||||
Convenient in package lists. Avoid at the top of a file — it silently shadows names and makes debugging hard.
|
Convenient in package lists. Avoid at the top of a file: it silently shadows names and makes debugging hard.
|
||||||
|
|
||||||
### Laziness
|
### Laziness
|
||||||
|
|
||||||
Nothing is evaluated until needed. This is why you can have huge attrsets like `nixpkgs` (100k+ packages) and only pay for what you use.
|
Nothing is evaluated until needed. This is why you can have large attrsets like `nixpkgs` (100k+ packages) and only pay for what you use.
|
||||||
|
|
||||||
```nix
|
```nix
|
||||||
let broken = throw "nope"; ok = 1; in ok # => 1, never evaluates `broken`
|
let broken = throw "nope"; ok = 1; in ok # => 1, never evaluates `broken`
|
||||||
@ -105,7 +105,7 @@ import ./foo.nix { x = 1; } # if foo.nix is a function, also call it
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Derivations — the core primitive
|
## 3. Derivations: The Core Primitive
|
||||||
|
|
||||||
A **derivation** is "a build, described as data." You create one with `derivation { … }` (low-level) or `pkgs.stdenv.mkDerivation { … }` (the nixpkgs wrapper you'll actually use).
|
A **derivation** is "a build, described as data." You create one with `derivation { … }` (low-level) or `pkgs.stdenv.mkDerivation { … }` (the nixpkgs wrapper you'll actually use).
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ Minimal example:
|
|||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
pname = "hello-note";
|
pname = "hello-note";
|
||||||
version = "0.1";
|
version = "0.1";
|
||||||
src = ./.; # path — gets copied into the store
|
src = ./.; # path: gets copied into the store
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
echo '#!/bin/sh' > $out/bin/hello-note
|
echo '#!/bin/sh' > $out/bin/hello-note
|
||||||
@ -132,40 +132,40 @@ Key ideas:
|
|||||||
- **`$out`** is the output store path the build writes into.
|
- **`$out`** is the output store path the build writes into.
|
||||||
- **Phases** (`unpackPhase`, `buildPhase`, `installPhase`, …) are shell snippets `stdenv` runs in order. Override the ones you need.
|
- **Phases** (`unpackPhase`, `buildPhase`, `installPhase`, …) are shell snippets `stdenv` runs in order. Override the ones you need.
|
||||||
- **No network** in the build sandbox, except for fixed-output derivations (whose hash you declare up front).
|
- **No network** in the build sandbox, except for fixed-output derivations (whose hash you declare up front).
|
||||||
- **Every input** — source, compiler, env vars — becomes part of the hash. Change anything and you get a fresh store path.
|
- **Every input** (source, compiler, env vars) becomes part of the hash. Change anything and you get a fresh store path.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Store model: why this is all different
|
## 4. Store Model: Why This Is All Different
|
||||||
|
|
||||||
Traditional package managers put files in `/usr/bin`, `/usr/lib`, etc. One version at a time. Upgrades mutate shared state.
|
Traditional package managers put files in `/usr/bin`, `/usr/lib`, and similar shared locations. One version at a time. Upgrades mutate shared state.
|
||||||
|
|
||||||
Nix puts every build in `/nix/store/<hash>-<name>/` with the hash derived from **all its inputs** (recursively). That gives you:
|
Nix puts every build in `/nix/store/<hash>-<name>/` with the hash derived from **all its inputs** (recursively). That gives you:
|
||||||
|
|
||||||
- **Atomic upgrades / rollbacks** — switching "versions" is just switching symlinks.
|
- **Atomic upgrades and rollbacks**: switching "versions" is just switching symlinks.
|
||||||
- **Multiple versions coexisting** — they live at different hashes.
|
- **Multiple versions coexisting**: they live at different hashes.
|
||||||
- **Reproducibility** — same inputs → same hash → same output (in theory; in practice, 99% there).
|
- **Reproducibility**: same inputs produce the same hash and the same output (in theory; in practice, 99% there).
|
||||||
- **Binary caching** — if someone else already built exactly these inputs, you can download their output. This is what `cache.nixos.org` does.
|
- **Binary caching**: if someone else already built exactly these inputs, you can download their output. This is what `cache.nixos.org` does.
|
||||||
- **Garbage-collectable** — anything not referenced by a "GC root" can be deleted safely.
|
- **Garbage-collectable**: anything not referenced by a "GC root" can be deleted safely.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. How you'll actually use Nix day-to-day
|
## 5. How You'll Actually Use Nix Day-to-Day
|
||||||
|
|
||||||
Ordered roughly by power-to-complexity:
|
Ordered roughly by power-to-complexity:
|
||||||
|
|
||||||
1. **`nix run nixpkgs#cowsay -- moo`** — run a package without installing.
|
1. **`nix run nixpkgs#cowsay -- moo`**: run a package without installing.
|
||||||
2. **`nix shell nixpkgs#jq nixpkgs#ripgrep`** — throwaway shell with those tools.
|
2. **`nix shell nixpkgs#jq nixpkgs#ripgrep`**: throwaway shell with those tools.
|
||||||
3. **Dev shell via `flake.nix`** — per-project pinned toolchain. *This is the most common thing flakes are used for.*
|
3. **Dev shell via `flake.nix`**: per-project pinned toolchain. *This is the most common thing flakes are used for.*
|
||||||
4. **`nix build`** — produce artifacts (binaries, containers, ISOs).
|
4. **`nix build`**: produce artifacts (binaries, containers, and ISOs).
|
||||||
5. **NixOS** — declare your whole OS config (packages, services, users, network) in Nix.
|
5. **NixOS**: declare your whole OS config (packages, services, users, and network) in Nix.
|
||||||
6. **home-manager** — same idea, at the user level.
|
6. **home-manager**: same idea, at the user level.
|
||||||
|
|
||||||
Each step up locks in more of your environment. You don't need to adopt all of it at once.
|
Each step up locks in more of your environment. You don't need to adopt all of it at once.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Minimum useful commands
|
## 6. Minimum Useful Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Language / introspection
|
# Language / introspection
|
||||||
@ -187,7 +187,7 @@ nix why-depends ./result nixpkgs#glibc # trace dependency chains
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Gotchas that trip up newcomers
|
## 7. Gotchas That Trip Up Newcomers
|
||||||
|
|
||||||
- **Lists use spaces, not commas.** `[ 1 2 3 ]`. Commas are a syntax error.
|
- **Lists use spaces, not commas.** `[ 1 2 3 ]`. Commas are a syntax error.
|
||||||
- **`rec { }`** makes an attrset self-referential. Without `rec`, attrs can't reference each other. You'll see this in package definitions.
|
- **`rec { }`** makes an attrset self-referential. Without `rec`, attrs can't reference each other. You'll see this in package definitions.
|
||||||
@ -198,8 +198,8 @@ nix why-depends ./result nixpkgs#glibc # trace dependency chains
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. What to read/try next
|
## 8. What to Read or Try Next
|
||||||
|
|
||||||
- Open `nix repl`, type `:l <nixpkgs>`, then `hello`, `hello.drv`, `hello.outPath`. Poke around.
|
- Open `nix repl`, type `:l <nixpkgs>`, then `hello`, `hello.drv`, `hello.outPath`. Poke around.
|
||||||
- Read [`nix.dev`](https://nix.dev) — the current best introduction.
|
- Read [`nix.dev`](https://nix.dev), the current best introduction.
|
||||||
- See `003-flakes.md` for the flakes-specific layer on top of all of this.
|
- See `003-flakes.md` for the flakes-specific layer on top of all of this.
|
||||||
|
|||||||
@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
A **flake** is a directory containing `flake.nix` (and, once evaluated, `flake.lock`). It's a packaging convention on top of regular Nix that gives you:
|
A **flake** is a directory containing `flake.nix` (and, once evaluated, `flake.lock`). It's a packaging convention on top of regular Nix that gives you:
|
||||||
|
|
||||||
- **Pinned inputs** via `flake.lock` → reproducible builds.
|
- **Pinned inputs** via `flake.lock` for reproducible builds.
|
||||||
- **A fixed output schema** → tools know where to look (`devShells.<system>.default`, `packages.<system>.default`, etc.).
|
- **A fixed output schema** so tools know where to look (`devShells.<system>.default`, `packages.<system>.default`, and so on).
|
||||||
- **Composability** → flakes depend on other flakes by URL.
|
- **Composability**, since flakes depend on other flakes by URL.
|
||||||
- **Pure evaluation** → no silent dependence on `NIX_PATH`, env vars, or random files.
|
- **Pure evaluation**, with no silent dependence on `NIX_PATH`, env vars, or random files.
|
||||||
|
|
||||||
Flakes are still marked "experimental" but are overwhelmingly the way new Nix code is written.
|
Flakes are still marked "experimental" but are now the way most new Nix code is written.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ Flakes are still marked "experimental" but are overwhelmingly the way new Nix co
|
|||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils, ... }: {
|
outputs = { self, nixpkgs, flake-utils, ... }: {
|
||||||
# arbitrary attrs here — but names with meaning to `nix` CLI must match the schema
|
# arbitrary attrs here, but names with meaning to `nix` CLI must match the schema
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -60,8 +60,8 @@ A function: `{ self, ...inputs }: <attrset>`. The attrset keys are *conventions*
|
|||||||
|
|
||||||
| Output path | What it is | Command |
|
| Output path | What it is | Command |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `devShells.<system>.<name>` | A `mkShell` — dev environment | `nix develop [.#<name>]` |
|
| `devShells.<system>.<name>` | A `mkShell`, a dev environment | `nix develop [.#<name>]` |
|
||||||
| `packages.<system>.<name>` | A derivation — build target | `nix build [.#<name>]` |
|
| `packages.<system>.<name>` | A derivation, a build target | `nix build [.#<name>]` |
|
||||||
| `apps.<system>.<name>` | `{ type = "app"; program = …; }` | `nix run [.#<name>]` |
|
| `apps.<system>.<name>` | `{ type = "app"; program = …; }` | `nix run [.#<name>]` |
|
||||||
| `nixosConfigurations.<host>` | `nixpkgs.lib.nixosSystem { … }` | `nixos-rebuild switch --flake .#<host>` |
|
| `nixosConfigurations.<host>` | `nixpkgs.lib.nixosSystem { … }` | `nixos-rebuild switch --flake .#<host>` |
|
||||||
| `homeConfigurations.<user>` | home-manager config | `home-manager switch --flake .#<user>` |
|
| `homeConfigurations.<user>` | home-manager config | `home-manager switch --flake .#<user>` |
|
||||||
@ -73,13 +73,13 @@ A function: `{ self, ...inputs }: <attrset>`. The attrset keys are *conventions*
|
|||||||
|
|
||||||
Default attrs `default` are picked when you omit the name: `nix build` ≡ `nix build .#default`.
|
Default attrs `default` are picked when you omit the name: `nix build` ≡ `nix build .#default`.
|
||||||
|
|
||||||
`.<system>` is the platform triple: `x86_64-linux`, `aarch64-linux`, `aarch64-darwin`, `x86_64-darwin`.
|
`.<system>` is the platform triple: `x86_64-linux`, `aarch64-linux`, `aarch64-darwin`, or `x86_64-darwin`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. The lockfile
|
## 2. The Lockfile
|
||||||
|
|
||||||
`flake.lock` pins the exact commit + NAR hash of every input, transitively. Generated/updated automatically on first use or `nix flake update`.
|
`flake.lock` pins the exact commit and NAR hash of every input, transitively. Generated or updated automatically on first use or via `nix flake update`.
|
||||||
|
|
||||||
- **Commit it.** Without it, "my flake" means different things on different machines.
|
- **Commit it.** Without it, "my flake" means different things on different machines.
|
||||||
- **Update explicitly.** `nix flake update` (all inputs) or `nix flake update nixpkgs` (one input).
|
- **Update explicitly.** `nix flake update` (all inputs) or `nix flake update nixpkgs` (one input).
|
||||||
@ -88,7 +88,7 @@ Default attrs `default` are picked when you omit the name: `nix build` ≡ `nix
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Multi-system support
|
## 3. Multi-System Support
|
||||||
|
|
||||||
A flake output has to enumerate systems explicitly. Two common patterns:
|
A flake output has to enumerate systems explicitly. Two common patterns:
|
||||||
|
|
||||||
@ -121,11 +121,11 @@ outputs = { self, nixpkgs, flake-utils }:
|
|||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
Less boilerplate, but adds a dependency. For bigger projects, `flake-parts` is increasingly popular — it gives you a module system for flakes themselves.
|
Less boilerplate, at the cost of one dependency. For larger projects, `flake-parts` is increasingly popular: it gives you a module system for flakes themselves.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Flake URIs: `.#<name>` syntax
|
## 4. Flake URIs: `.#<name>` Syntax
|
||||||
|
|
||||||
Everywhere you point `nix` at a flake, the form is `<flake-ref>#<attr>`:
|
Everywhere you point `nix` at a flake, the form is `<flake-ref>#<attr>`:
|
||||||
|
|
||||||
@ -138,26 +138,26 @@ nix run nixpkgs#hello # pkgs.hello from the nixpkgs registry flake
|
|||||||
nixos-rebuild switch --flake .#my-host
|
nixos-rebuild switch --flake .#my-host
|
||||||
```
|
```
|
||||||
|
|
||||||
The `<system>` portion is auto-inferred from your machine — you don't spell it out in the CLI.
|
The `<system>` portion is auto-inferred from your machine; you don't spell it out in the CLI.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Pure evaluation — what you lose, what you gain
|
## 5. Pure Evaluation: What You Lose, What You Gain
|
||||||
|
|
||||||
Flakes evaluate in pure mode:
|
Flakes evaluate in pure mode:
|
||||||
|
|
||||||
- No reading `NIX_PATH` or `<nixpkgs>`.
|
- No reading `NIX_PATH` or `<nixpkgs>`.
|
||||||
- No arbitrary `builtins.getEnv` or reading files outside the flake.
|
- No arbitrary `builtins.getEnv` or reading files outside the flake.
|
||||||
- `builtins.currentTime` / `currentSystem` are blocked.
|
- `builtins.currentTime` and `builtins.currentSystem` are blocked.
|
||||||
- Source is pulled from the flake's input tree, not the working directory, unless you're in `self`. Files not tracked by git are **invisible** to the flake by default.
|
- Source is pulled from the flake's input tree, not the working directory, unless you're in `self`. Files not tracked by git are **invisible** to the flake by default.
|
||||||
|
|
||||||
This last point surprises people: **`git add` a file before `nix build` can see it.** (`nix build --impure` escapes this, but then you're not reproducible.)
|
This last point surprises people: **`git add` a file before `nix build` can see it.** (`nix build --impure` escapes this, but then you're not reproducible.)
|
||||||
|
|
||||||
In exchange: anyone with your `flake.nix` + `flake.lock` gets bit-identical evaluation.
|
In exchange: anyone with your `flake.nix` plus `flake.lock` gets bit-identical evaluation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. Common commands
|
## 6. Common Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
nix flake init # scaffold a flake.nix in current dir
|
nix flake init # scaffold a flake.nix in current dir
|
||||||
@ -176,9 +176,9 @@ nix run # run apps.<sys>.default (or packages.<sys>.d
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Recurring patterns worth recognizing
|
## 7. Recurring Patterns Worth Recognizing
|
||||||
|
|
||||||
### Rust / Go / Python dev shell
|
### Rust / Go / Python Dev Shell
|
||||||
```nix
|
```nix
|
||||||
devShells.default = pkgs.mkShell {
|
devShells.default = pkgs.mkShell {
|
||||||
packages = [ pkgs.cargo pkgs.rustc pkgs.rust-analyzer ];
|
packages = [ pkgs.cargo pkgs.rustc pkgs.rust-analyzer ];
|
||||||
@ -187,7 +187,7 @@ devShells.default = pkgs.mkShell {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Package a local source tree
|
### Package a Local Source Tree
|
||||||
```nix
|
```nix
|
||||||
packages.default = pkgs.rustPlatform.buildRustPackage {
|
packages.default = pkgs.rustPlatform.buildRustPackage {
|
||||||
pname = "my-tool";
|
pname = "my-tool";
|
||||||
@ -197,13 +197,13 @@ packages.default = pkgs.rustPlatform.buildRustPackage {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
### Expose a NixOS module
|
### Expose a NixOS Module
|
||||||
```nix
|
```nix
|
||||||
nixosModules.default = import ./module.nix;
|
nixosModules.default = import ./module.nix;
|
||||||
# Consumer does: imports = [ inputs.my-flake.nixosModules.default ];
|
# Consumer does: imports = [ inputs.my-flake.nixosModules.default ];
|
||||||
```
|
```
|
||||||
|
|
||||||
### NixOS system config as a flake
|
### NixOS System Config as a Flake
|
||||||
```nix
|
```nix
|
||||||
nixosConfigurations.my-laptop = nixpkgs.lib.nixosSystem {
|
nixosConfigurations.my-laptop = nixpkgs.lib.nixosSystem {
|
||||||
system = "x86_64-linux";
|
system = "x86_64-linux";
|
||||||
@ -212,7 +212,7 @@ nixosConfigurations.my-laptop = nixpkgs.lib.nixosSystem {
|
|||||||
# Apply with: nixos-rebuild switch --flake .#my-laptop
|
# Apply with: nixos-rebuild switch --flake .#my-laptop
|
||||||
```
|
```
|
||||||
|
|
||||||
### Overlay as an output
|
### Overlay as an Output
|
||||||
```nix
|
```nix
|
||||||
overlays.default = final: prev: {
|
overlays.default = final: prev: {
|
||||||
my-patched-foo = prev.foo.overrideAttrs (old: { … });
|
my-patched-foo = prev.foo.overrideAttrs (old: { … });
|
||||||
@ -221,21 +221,21 @@ overlays.default = final: prev: {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Debugging tips
|
## 8. Debugging Tips
|
||||||
|
|
||||||
- **`nix flake show --all-systems`** to see outputs for every platform, not just yours.
|
- **`nix flake show --all-systems`** to see outputs for every platform, not just yours.
|
||||||
- **`nix eval .#packages.x86_64-linux.default.drvPath`** to get the `.drv` without building.
|
- **`nix eval .#packages.x86_64-linux.default.drvPath`** to get the `.drv` without building.
|
||||||
- **`nix eval --json .#devShells.x86_64-linux.default.buildInputs | jq`** to inspect shell deps.
|
- **`nix eval --json .#devShells.x86_64-linux.default.buildInputs | jq`** to inspect shell deps.
|
||||||
- **`--show-trace`** on any command for full eval backtraces.
|
- **`--show-trace`** on any command for full eval backtraces.
|
||||||
- **`nix repl .`** loads your flake's outputs into a REPL — great for poking at attrs.
|
- **`nix repl .`** loads your flake's outputs into a REPL: useful for poking at attrs.
|
||||||
- If an input seems stuck on an old rev, check `flake.lock`; `nix flake update <name>` fixes it.
|
- If an input seems stuck on an old rev, check `flake.lock`; `nix flake update <name>` fixes it.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. When flakes are overkill
|
## 9. When Flakes Are Overkill
|
||||||
|
|
||||||
- Running a one-off tool: `nix run nixpkgs#ripgrep` — no flake needed.
|
- Running a one-off tool: `nix run nixpkgs#ripgrep`, no flake needed.
|
||||||
- A tiny personal script: plain `default.nix` + `nix-build` is still fine.
|
- A tiny personal script: plain `default.nix` plus `nix-build` is still fine.
|
||||||
- Large monorepos with complex CI: consider `flake-parts` or hybrid setups (flake for the interface, regular Nix for guts).
|
- Large monorepos with complex CI: consider `flake-parts` or hybrid setups (flake for the interface, regular Nix for guts).
|
||||||
|
|
||||||
Flakes are a **packaging interface**, not a requirement. The old non-flake world still works — flakes just compose better once you have more than one Nix project.
|
Flakes are a **packaging interface**, not a requirement. The old non-flake world still works; flakes just compose better once you have more than one Nix project.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user