Nix Developer Shells · Workshop Lektion 6 / Flakes & mkShell

mkShell I: deine erste Dev-Shell

Der Moment, auf den der Kurs hinarbeitet: nix develop – und die Tools sind da.

Warum das zählt
Das ist das Herzstück deines Workshops. Ein git clone, ein nix develop – und jede:r Mitwirkende hat exakt dieselben Tools in exakt denselben Versionen. Kein „installier erst mal…" mehr. Heute baust du genau diese Shell.

Was mkShell macht

pkgs.mkShell ist eine Funktion (Lektion 3), die aus einem Set eine spezielle Derivation erzeugt: keine, die ein Programm baut, sondern eine, die eine Umgebung beschreibt. nix develop betritt sie und stellt alle genannten Pakete in den PATH.

Die minimale Dev-Shell

Wir nehmen das Flake aus Lektion 5 und schauen genau auf den devShells-Teil:

  outputs = { self, nixpkgs }:
    let
      system = "x86_64-linux";
      pkgs   = nixpkgs.legacyPackages.${system};
    in {
      devShells.${system}.default = pkgs.mkShell {
        packages = [
          pkgs.git
          pkgs.jq
          pkgs.go
        ];
      };
    };

Die Shell betreten

$ cd toolbox
$ nix develop

# jetzt sind git, jq und go verfügbar – exakt diese Versionen
$ go version
go version go1.22.x linux/amd64
$ which jq
/nix/store/…-jq-1.7.1/bin/jq        # aus dem Store, nicht vom System

# wie bei nix shell: exit → alles wieder weg, System unverändert
$ exit

Vergleiche mit Lektion 1: Damals war es eine ad-hoc-Shell (nix shell nixpkgs#…). Jetzt ist dieselbe Idee deklarativ in einer Datei festgehalten, versioniert und teilbar. Das ist der ganze Unterschied zwischen „kurz ausprobieren" und „Projekt-Umgebung".

default und benannte Shells

nix develop ohne Argument nimmt devShells.<system>.default. Du kannst weitere Shells benennen und gezielt betreten:

      devShells.${system} = {
        default = pkgs.mkShell { packages = [ pkgs.go ]; };
        ci      = pkgs.mkShell { packages = [ pkgs.go pkgs.golangci-lint ]; };
      };
# Aufruf:  nix develop .#ci
Dein Win Du hast eine echte, geteilte Dev-Umgebung gebaut. Das ist die Kernfähigkeit aus deiner Mission – alles Weitere (mehr Kontrolle, Lock-Files, eigene Pakete) verfeinert nur noch dieses Fundament.

Besonderheiten & Stolperfallen

Du bist in bash, nicht in deiner Shell nix develop startet standardmäßig eine bash – nicht deine gewohnte zsh/fish mit Prompt & Aliases. Für eine vertraute Shell nimm nix develop -c $SHELL oder – viel komfortabler – direnv (Lektion 12).
mkShell baut man nicht mit nix build Eine Dev-Shell ist zum Betreten da, nicht zum Bauen eines Ergebnisses. nix build auf eine devShell ist selten sinnvoll – nutze nix develop.
packages ist der moderne Schlüssel Du wirst in alten Beispielen buildInputs statt packages sehen. Für reine Tool-Listen ist packages heute der empfohlene, klarere Weg. Den Unterschied zu nativeBuildInputs klären wir in Lektion 7.

Kurz prüfen (aus dem Kopf)

Nicht spicken – Abrufen aus dem Gedächtnis ist genau die Übung, die hängen bleibt.

Welchen Output sucht nix develop ohne Argument?

Was ist der Kernunterschied zu nix shell nixpkgs#go?

Warum sieht dein Prompt nach nix develop „nackt" aus?

Übung für Teilnehmende

Ziel: Die toolbox-Shell betreten und beweisen, dass die Tools aus dem Store kommen.

  1. Erweitere die packages-Liste deines Flakes um pkgs.go und pkgs.jq.
  2. git add nicht vergessen, dann nix develop.
  3. Prüfe mit which go und which jq, dass beide unter /nix/store/ liegen.
  4. Verlasse die Shell und prüfe, dass go draußen fehlt (oder eine andere Version ist).

Tipp: Füge testweise eine zweite, benannte Shell .#ci hinzu und betritt sie gezielt.

Lösung anzeigen
$ git add flake.nix
$ nix develop
$ which go
/nix/store/…-go-1.22.x/bin/go
$ which jq
/nix/store/…-jq-1.7.1/bin/jq
$ exit
$ which go        # weg oder System-Version – nicht der Store-Pfad

Genau dieser Store-Pfad ist die Garantie, dass alle im Team dieselben Versionen nutzen.

Primärquelle zum Lesen nix.dev – Declarative shell environments. Baut dieselbe Idee Schritt für Schritt auf. Lies sie als zweite Perspektive auf das, was du gerade gebaut hast.
Ich bin dein Teacher. Deine Shell startet nicht, oder ein Tool fehlt trotz Eintrag? Schick mir deine flake.nix und die Fehlermeldung – wir finden es zusammen.
← Lektion 5 · Flakes-Grundlagen Lektion 7 · mkShell II →
Als Nächstes: Lektion 7 – mkShell II (packages vs nativeBuildInputs, shellHook, env vars)