Le store Nix (/nix/store/) est le cœur du système : chaque paquet y vit
dans un répertoire unique identifié par un hash cryptographique. Deux
installations identiques produisent exactement le même chemin, deux versions
différentes cohabitent sans conflit. Au-dessus, les profils exposent les
binaires via des liens symboliques, et les générations gardent un
historique complet qui permet un rollback instantané. Ce modèle élimine les
conflits de dépendances, rend chaque opération atomique et permet de récupérer
l’espace disque à la demande.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Comprendre la structure du store Nix et le rôle du hash dans chaque chemin
- Explorer un paquet dans le store et sa closure (arbre de dépendances complet)
- Manipuler les profils utilisateur et voir comment les binaires sont exposés
- Créer, lister et basculer entre les générations
- Effectuer un rollback instantané vers un état précédent
- Libérer de l’espace avec le garbage collector et l’optimisation du store
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »Quand vous installez un paquet avec nix profile add, vous ne touchez pas aux
répertoires système classiques (/usr/bin, /usr/lib). Le paquet atterrit dans
le store, et un lien symbolique apparaît dans votre profil. Comprendre ce
mécanisme est indispensable pour :
- diagnostiquer pourquoi un binaire n’est pas trouvé après installation,
- libérer de l’espace disque sans casser les paquets actifs,
- revenir en arrière après une mise à jour ratée,
- partager un environnement reproductible entre machines,
- comprendre les closures pour optimiser la taille de vos déploiements.
Le store : /nix/store/
Section intitulée « Le store : /nix/store/ »Un répertoire, un hash
Section intitulée « Un répertoire, un hash »Chaque élément du store Nix vit dans un chemin de la forme :
/nix/store/<hash-32-caractères>-<nom>-<version>Le hash est calculé à partir de toutes les entrées de la construction : code source, dépendances, flags de compilation, patches. Si l’une de ces entrées change, le hash change — et un nouveau chemin est créé.
ls /nix/store/ | grep ripgrep922crn2k3v8yaqk7anps80hba919lnds-ripgrep-15.1.0Anatomie d’un paquet dans le store
Section intitulée « Anatomie d’un paquet dans le store »Chaque répertoire du store suit une structure FHS-like (mais isolée) :
ls -la /nix/store/922crn2k3v8yaqk7anps80hba919lnds-ripgrep-15.1.0/dr-xr-xr-x 4 root root 4096 Jan 1 1970 .dr-xr-xr-x 2 root root 4096 Jan 1 1970 bindr-xr-xr-x 6 root root 4096 Jan 1 1970 shareLe binaire rg est dans bin/, les pages man dans share/. Mais contrairement
à un paquet Debian ou RPM, rien n’est copié dans /usr/bin — le paquet vit
exclusivement dans le store.
Immuabilité du store
Section intitulée « Immuabilité du store »Les répertoires du store sont en lecture seule (dr-xr-xr-x). Une fois
construit, un paquet ne peut plus être modifié — seulement supprimé par le
garbage collector. Cette immuabilité garantit qu’aucun processus ne peut
corrompre silencieusement une dépendance.
Taille du store
Section intitulée « Taille du store »Après quelques installations, le store grandit vite car chaque paquet embarque ses dépendances :
du -sh /nix/store/1.2G /nix/store/ls /nix/store/ | wc -l2242Ne vous inquiétez pas de cette taille : le garbage collector (décrit plus bas) permet de récupérer l’espace des paquets inutilisés.
Les closures : l’arbre complet de dépendances
Section intitulée « Les closures : l’arbre complet de dépendances »Une closure est l’ensemble de tous les chemins du store nécessaires pour
faire fonctionner un paquet. Quand Nix installe ripgrep, il ne télécharge pas
seulement le binaire — il s’assure que toutes ses dépendances (glibc, pcre2,
gcc-lib…) sont présentes dans le store.
nix path-info -rsSh /nix/store/922crn2k3v8yaqk7anps80hba919lnds-ripgrep-15.1.0/nix/store/p7jg95rzvfalb95k3mskk0jqxc9d724n-libunistring-1.4.1 2.0 MiB 2.0 MiB/nix/store/1ga782ml07vy0h503ac4cin0h8d7q6yh-libidn2-2.3.8 368.3 KiB 2.3 MiB/nix/store/hbnbbbx1n96v1waiiaid9fmg4li4i1kp-gcc-15.2.0-libgcc 193.1 KiB 193.1 KiB/nix/store/jms7zxzm7w1whczwny5m3gkgdjghmi2r-glibc-2.42-51 33.5 MiB 36.0 MiB/nix/store/ab3753m6i7isgvzphlar0a8xb84gl96i-gcc-15.2.0-lib 9.8 MiB 46.0 MiB/nix/store/ygdgqjzw03k8d05zq3pigzf67b62j7vs-pcre2-10.46 2.0 MiB 38.0 MiB/nix/store/922crn2k3v8yaqk7anps80hba919lnds-ripgrep-15.1.0 6.4 MiB 54.3 MiBLa colonne de gauche indique la taille propre du paquet, celle de droite sa
taille de closure (le paquet + toutes ses dépendances transitives). Ici,
ripgrep pèse 6.4 MiB mais sa closure complète atteint 54.3 MiB à cause
principalement de la glibc.
Les profils : exposer les binaires
Section intitulée « Les profils : exposer les binaires »La chaîne de liens symboliques
Section intitulée « La chaîne de liens symboliques »Installer un paquet ne copie rien dans /usr/bin. Nix crée une chaîne de
liens symboliques qui connecte votre $PATH au store :
~/.nix-profile → ~/.local/state/nix/profiles/profile └→ profile-2-link → /nix/store/nr80...-profile/ └→ bin/ ├── jq → /nix/store/fc13...-jq-1.8.1-bin/bin/jq └── rg → /nix/store/922c...-ripgrep-15.1.0/bin/rgVérifions dans le lab :
ls -la ~/.nix-profile~/.nix-profile -> /home/lab/.local/state/nix/profiles/profilels -la ~/.local/state/nix/profiles/profile -> profile-2-linkprofile-1-link -> /nix/store/ka87x2xwr14ry1c1nzcf5ii5lqmhfpla-profileprofile-2-link -> /nix/store/nr80jc6l6jp00c9s3imrvrfx258njr0p-profilels ~/.nix-profile/bin/jq rgChaque profile-N-link pointe vers un répertoire du store qui agrège tous
les paquets de cette génération. Quand vous ajoutez un paquet, Nix crée un
nouveau répertoire d’agrégation dans le store et fait pointer le lien
profile vers celui-ci.
Profil système vs profil utilisateur
Section intitulée « Profil système vs profil utilisateur »Nix gère deux niveaux de profils :
| Profil | Chemin | Usage |
|---|---|---|
| Utilisateur | ~/.local/state/nix/profiles/profile | Paquets installés par l’utilisateur courant |
| Système | /nix/var/nix/profiles/default | Paquets installés pour tout le système (inclut nix lui-même) |
Les générations : historique et rollback
Section intitulée « Les générations : historique et rollback »Chaque modification crée une génération
Section intitulée « Chaque modification crée une génération »À chaque ajout ou suppression de paquet, Nix crée une nouvelle génération du profil. L’ancienne génération reste intacte dans le store — rien n’est écrasé.
Installons jq et observons l’historique :
nix profile add nixpkgs#jqnix profile historyVersion 1 (2026-04-14): flake:nixpkgs#legacyPackages.x86_64-linux.ripgrep: ∅ -> 15.1.0
Version 2 (2026-04-14) <- 1: flake:nixpkgs#legacyPackages.x86_64-linux.jq: ∅ -> 1.8.1-bin, 1.8.1-manLa Version 1 contient uniquement ripgrep. La Version 2 ajoute jq et
référence la Version 1 comme parent (<- 1).
Rollback instantané
Section intitulée « Rollback instantané »Pour revenir à la génération précédente :
nix profile rollbackswitching profile from version 2 to 1Après rollback, seul rg est disponible dans le profil :
ls ~/.nix-profile/bin/rgjq a disparu du profil — mais il est toujours présent dans le store. Nix
n’a fait que changer le lien symbolique profile pour pointer vers
profile-1-link au lieu de profile-2-link.
Basculer vers une génération spécifique
Section intitulée « Basculer vers une génération spécifique »Pour revenir à la génération 2 :
nix profile rollback --to 2switching profile from version 1 to 2ls ~/.nix-profile/bin/jq rgLister les paquets du profil actif
Section intitulée « Lister les paquets du profil actif »nix profile listName: jqFlake attribute: legacyPackages.x86_64-linux.jqStore paths: /nix/store/crwv17pim6csnfr4jmsd7kf60sp3c5dh-jq-1.8.1-man /nix/store/fc13hvlj7541i1xmwdka7f61qicdzr5a-jq-1.8.1-bin
Name: ripgrepFlake attribute: legacyPackages.x86_64-linux.ripgrepStore paths: /nix/store/922crn2k3v8yaqk7anps80hba919lnds-ripgrep-15.1.0Libérer de l’espace : garbage collection et optimisation
Section intitulée « Libérer de l’espace : garbage collection et optimisation »Pourquoi le store grossit
Section intitulée « Pourquoi le store grossit »Le store accumule les paquets au fil du temps : anciennes générations, paquets
testés via nix shell, dépendances de build intermédiaires. Tant qu’une
racine GC (GC root) référence un chemin, il est protégé de la suppression.
Les racines GC principales sont :
- les générations de profil (
profile-1-link,profile-2-link…), - les résultats de
nix buildliés dans./result, - les profils système.
Supprimer les anciennes générations
Section intitulée « Supprimer les anciennes générations »Avant de lancer le garbage collector, supprimez les générations obsolètes pour les retirer des racines GC :
nix profile wipe-history --older-than 1dCette commande supprime toutes les générations de plus d’un jour. Seule la génération active est conservée.
Lancer le garbage collector
Section intitulée « Lancer le garbage collector »nix store gcdeleting '/nix/store/i4q069m3d29gi7dw1ijhjrp4hxw1c2l4-module-dir.patch'deleting '/nix/store/d77svhhwwqkvacx0gdyscjp4jdfjkh9d-gcc-15.patch'...deleting unused links...533 store paths deleted, 242.6 MiB freedLe GC a récupéré 242 MiB en supprimant 533 chemins qui n’étaient plus référencés par aucune racine.
du -sh /nix/store/660M /nix/store/Le store est passé de 1.2 Go à 660 Mo.
Optimiser le store par déduplication
Section intitulée « Optimiser le store par déduplication »Même après le GC, certains fichiers sont dupliqués entre paquets (bibliothèques
partagées, fichiers de configuration identiques). La commande optimise les
remplace par des hard links :
nix store optimise15.2 MiB freed by hard-linking 1230 filesdu -sh /nix/store/647M /nix/store/Récapitulatif des commandes de maintenance
Section intitulée « Récapitulatif des commandes de maintenance »| Commande | Effet |
|---|---|
nix profile wipe-history --older-than 7d | Supprime les générations de plus de 7 jours |
nix store gc | Supprime les chemins non référencés |
nix store optimise | Déduplique les fichiers identiques par hard links |
nix store gc --max 1G | Libère au maximum 1 Go |
Synthèse du modèle de données
Section intitulée « Synthèse du modèle de données »┌─────────────────────────────────────────────────┐│ Votre shell ││ $PATH contient ~/.nix-profile/bin/ │└────────────────────┬────────────────────────────┘ │ symlink┌────────────────────▼────────────────────────────┐│ Profil utilisateur ││ ~/.local/state/nix/profiles/profile ││ → profile-2-link (génération active) ││ → profile-1-link (ancienne, rollback possible) │└────────────────────┬────────────────────────────┘ │ symlink vers store┌────────────────────▼────────────────────────────┐│ /nix/store/ ││ nr80...-profile/bin/ → agrège les paquets ││ 922c...-ripgrep-15.1.0/bin/rg ││ fc13...-jq-1.8.1-bin/bin/jq ││ jms7...-glibc-2.42-51/lib/ ││ (immuable, identifié par hash) │└──────────────────────────────────────────────────┘À retenir
Section intitulée « À retenir »- Le store (
/nix/store/) contient tous les paquets, chacun identifié par un hash unique — deux versions cohabitent sans conflit. - Une closure est l’ensemble complet des dépendances d’un paquet ; c’est l’unité de déploiement de Nix.
- Les profils exposent les binaires via des chaînes de liens symboliques, sans toucher à
/usr/bin. - Chaque modification du profil crée une nouvelle génération ; le rollback est instantané et atomique.
- Le garbage collector ne supprime que les chemins sans racine GC — vos paquets actifs sont toujours protégés.
nix store optimisedéduplique les fichiers identiques par hard links pour réduire l’empreinte disque.