Le 13 octobre 2026, j’étais à la Brasserie du Digital pour une conférence BYOD consacrée à la fiabilité des systèmes. Dans la salle, une phrase a fait hocher la tête de tout le monde : « chez moi, ça fonctionne ».
Cette phrase, tout le monde l’a déjà entendue ou prononcée. Elle précède souvent l’arrivée d’un nouvel élément qui passe deux jours à tenter de compiler un projet, bloqué par une bibliothèque système absente ou une version mineure d’interpréteur qui diverge de celle du serveur.
Ce n’est pas un manque de rigueur des équipes. C’est le résultat mécanique de la conception même des systèmes d’exploitation traditionnels.
Un état qu’on ne sait pas décrire précisément ne se rejoue pas.
Tant qu’un système repose sur l’accumulation de modifications manuelles, il reste impossible à reproduire à l’identique d’une machine à l’autre.
Ce que ça change pour l’entreprise
Le sujet intéresse les équipes techniques, mais l’impact direct concerne l’exploitation et la trésorerie. Trois situations concrètes le résument.
L’arrivée d’une personne dans l’équipe. Un poste de travail configuré en deux commandes (git clone, puis devenv shell) remplace la demi-journée passée à aligner les versions de compilateurs et de bases locales. Les dépendances sont verrouillées dans le dépôt : chacun travaille rigoureusement sur le même environnement.
La mise à jour de production. L’ancien état reste intact sur le disque à côté du nouveau. Décider d’une mise à jour ne ressemble plus à la roulette des redémarrages Windows du mardi soir, où l’on guette l’écran en espérant éviter un « Annulation des modifications » interminable. L’ancienne version reste disponible : si un service échoue, le retour arrière prend quinze secondes au redémarrage.
Le départ de la personne qui sait. Le serveur monté il y a six ans par un administrateur n’est plus une boîte noire qui vit dans sa mémoire. L’état entier de la machine est consigné dans un fichier texte versionné, lisible et comparable par n’importe quel membre compétent de l’équipe.
Deux limites doivent être posées avec franchise : la bascule logicielle ne dispense pas de gérer les données applicatives (voir plus bas la section sur le stockage), et NixOS demande un véritable apprentissage. C’est pourquoi l’adoption gagne toujours à être progressive : d’abord sur un projet précis, sans toucher au système hôte.
Pourquoi un système classique casse
Dans un système Linux traditionnel, l’administration repose sur la mutation. Modifier une machine consiste à altérer ses fichiers en place : installer un paquet avec le gestionnaire de la distribution, éditer un fichier dans /etc, exécuter un script d’ajustement.
Chaque commande modifie un état existant. Même si deux machines partent d’une installation strictement identique, quelques mois d’exploitation suffisent pour que leurs configurations divergent de façon invisible.
Préparer et activer : la confusion d’origine
Dans une mise à jour ordinaire, deux opérations distinctes s’exécutent en même temps : la préparation du nouvel état et son activation. Le gestionnaire de paquets télécharge des fichiers et écrase immédiatement les binaires et les bibliothèques en cours d’utilisation sur le disque.
Si l’opération est interrompue par une coupure réseau, un disque saturé ou un script de pré-installation défaillant, le système se retrouve au milieu du gué. Certains fichiers appartiennent à l’ancienne version, d’autres à la nouvelle.
Le retour arrière devient alors un travail d’archéologie : il faut deviner ce qui a été modifié pour tenter de restaurer manuellement l’état antérieur.
Le principe du système immuable
L’approche immuable applique au système d’exploitation ce que les développeurs utilisent quotidiennement avec Git : un état figé, identifié, auquel on peut revenir à tout moment.
La règle fondamentale est simple : on ne modifie jamais un système en place.
Le nouvel état est construit et vérifié intégralement à côté de l’état actif, sans toucher aux processus en cours d’exécution. Lorsque tout est prêt, une bascule atomique active la nouvelle version.
Une opération atomique / « tout ou rien » s’exécute en un seul bloc, sans aucun état intermédiaire observable par les processus. Par exemple : si on débranche la prise électrique au beau milieu de la bascule, le système redémarrera soit sur l’ancienne version, soit sur la nouvelle, mais jamais dans un état hybride ou corrompu.
En cas d’anomalie au démarrage ou pendant les tests de validation, le retour à l’état précédent prend quelques secondes : il suffit de pointer à nouveau vers l’ancienne génération.
Trois façons d’aborder l’immuabilité
L’immuabilité s’implémente à différents niveaux d’abstraction, du disque brut jusqu’au paquet logiciel. Trois approches dominent aujourd’hui le paysage technique.
1. Le partitionnement A/B
C’est l’approche retenue par Android, ChromeOS et certaines distributions spécialisées. Le disque comporte deux partitions système identiques, A et B.
Pendant que la partition A fonctionne, le système télécharge et écrit l’image complète de la mise à jour sur la partition B. Au redémarrage suivant, l’amorceur (bootloader) tente de démarrer sur B et exécute des contrôles de santé.
Si les tests réussissent, la partition B devient la référence. Si le démarrage échoue, la machine bascule automatiquement sur la partition A.
Cette mécanique est redoutablement efficace pour des terminaux autonomes ou des flottes d’objets connectés. En revanche, elle montre vite ses limites sur des serveurs : elle double l’espace disque requis et impose de manipuler des images monolithiques complètes, peu adaptées au sur-mesure.
2. L’arbre de fichiers versionné avec OSTree
Popularisé par l’écosystème Fedora Silverblue, OSTree applique les principes de Git à l’arborescence des fichiers du système d’exploitation.
Les fichiers système résident dans un dépôt adressé par contenu. Chaque déploiement constitue une révision en lecture seule, et les anciens déploiements restent accessibles au menu de démarrage de la machine. Les applications utilisateur sont quant à elles isolées dans des conteneurs (Flatpak ou Distrobox).
Le revers d’OSTree réside dans sa rigidité. La granularité reste celle d’une image fournie par un éditeur tiers. Pour ajouter un paquet système non prévu, il faut superposer des couches (layering via rpm-ostree), ce qui ralentit la recomposition de l’image et fragilise la reproductibilité de l’ensemble.
L’état final dépend de ce que produit l’éditeur, et non d’une déclaration locale exhaustive : c’est un compromis intermédiaire entre immuabilité et gestion classique.
3. La dérivation fonctionnelle avec Nix et NixOS
L’approche de Nix pousse l’exigence jusqu’au bout. Nix ne raisonne ni en partitions, ni en images : il traite chaque paquet logiciel comme le résultat d’une fonction pure et déterministe.
Une recette Nix prend des entrées explicites (sources figées par une empreinte cryptographique, dépendances, options de compilation) et produit une dérivation (.drv). L’évaluation de cette dérivation génère un chemin unique et immuable dans le magasin de paquets :
/nix/store/<empreinte>-hello-2.12.1
Puisque l’empreinte dépend rigoureusement de toutes les entrées, deux compilations d’un même logiciel avec des versions différentes de compilateur (par exemple GCC 12 et GCC 13) cohabitent dans /nix/store sans aucun conflit de bibliothèques. La variable $PATH se compose selon le contexte déclaré et détermine quelle version s’exécute.
Modifier une entrée change les chemins qui en dérivent : seul le strict nécessaire est reconstruit, le reste est réutilisé.
NixOS étend ce principe à l’intégralité du système d’exploitation. Un fichier de configuration, une unité systemd, un compte utilisateur ou le noyau Linux sont tous des dérivations assemblées dans le magasin de paquets.
Le système actif n’est qu’un ensemble de liens symboliques pointant vers ces chemins immuables.
Le magasin immuable et le rôle du démon
Pour garantir qu’aucun processus ni utilisateur ne modifie les fichiers par mégarde, le répertoire /nix/store est monté strictement en lecture seule.
Toutes les écritures passent par un service d’arrière-plan unique : le nix-daemon. Lorsqu’un utilisateur lance une commande de construction, sa requête est transmise au démon.
Ce dernier délègue le travail à des comptes système dédiés et isolés (nixbld1, nixbld2…), sans privilèges d’administration et surtout sans accès réseau. Aucun script de construction ne peut télécharger des dépendances cachées en cours de route : toutes les sources doivent avoir été déclarées et vérifiées au préalable par leur empreinte cryptographique.
Une fois la construction achevée avec succès dans ce bac à sable hermétique, le résultat est inséré de façon atomique dans le magasin.
Modules nixpkgs : une intention, plusieurs dérivations
Tout écrire soi-même à partir de zéro serait fastidieux. C’est le rôle de nixpkgs, le dépôt communautaire qui contient les recettes prêtes à l’emploi.
On y trouve des paquets individuels, mais surtout des modules. Un module expose des options de haut niveau et génère pour vous l’ensemble des dérivations nécessaires :
services.postgresql = {
enable = true;
port = 5434;
};
Cette simple déclaration produit automatiquement :
- le paquet PostgreSQL avec ses dépendances binaires ;
- les fichiers de configuration associés (
postgresql.conf,pg_hba.conf) ; - l’unité de service systemd ;
- la création de l’utilisateur et du groupe système requis.
L’administrateur déclare l’intention, le module assemble les recettes.
Le plus grand catalogue de paquets
Avec environ 115 000 paquets dans sa branche stable (source Repology, octobre 2026), nixpkgs dépasse largement les distributions classiques comme Debian (~38 000 paquets) ou Ubuntu (~40 000 paquets).
Il intègre environ 23 500 paquets libres, et environ 1 100 paquets sous licence propriétaire (comme certains pilotes matériels ou suites logicielles). Par défaut, Nix refuse d’évaluer ou d’installer un paquet non libre si l’administrateur ne l’a pas explicitement autorisé via config.allowUnfree = true. Si une seule dépendance transitive d’un paquet est non libre, le garde-fou bloque la chaîne.
Le cache binaire officiel
Reconstruire chaque binaire localement paralyserait l’exploitation. Le système s’appuie donc sur un serveur de cache binaire officiel (cache.nixos.org).
Puisqu’une dérivation calcule l’empreinte de son chemin de sortie avant même de compiler, la machine interroge le cache avec cette empreinte : si le binaire précompilé s’y trouve, il est simplement téléchargé. La compilation locale n’intervient que pour du code sur mesure ou des options modifiées.
Cette mécanique repose sur deux piliers matériels : des sources figées par leur empreinte et des outils de construction déterministes. Elle ne tient que tant que ces deux conditions le restent.
La rupture avec le standard FHS (Filesystem Hierarchy Standard)
Ce modèle a une contrepartie technique majeure : Nix brise délibérément le standard FHS. Sur NixOS, les répertoires /usr/bin, /bin et /lib n’existent pas sous leur forme habituelle. Seuls /bin/sh et /usr/bin/env sont conservés pour assurer la compatibilité des scripts (qui doivent utiliser l’en-tête #! /usr/bin/env bash plutôt que #! /bin/bash).
Le chargeur dynamique dédié à chaque programme
Sous Linux, un exécutable compilé utilise le format ELF (Executable and Linkable Format). Son en-tête contient deux métadonnées essentielles : le chemin de son interpréteur de programme dynamique (le chargeur) et la liste des bibliothèques partagées (.so) requises.
Sur un système Linux ordinaire, tous les programmes partagent le même chargeur dynamique global (/lib64/ld-linux-x86-64.so.2) et vont chercher leurs bibliothèques au même endroit (/lib, /usr/lib). C’est l’origine directe du fameux « enfer des dépendances ».
Pour les mainteneurs d’une distribution classique, c’est un casse-tête permanent : il faut garantir qu’au sein du dépôt officiel, tous les paquets disponibles dépendent rigoureusement de la même version d’une bibliothèque partagée (comme Qt, GTK ou OpenSSL). Dès qu’un logiciel réclame une version plus récente ou plus ancienne, l’alignement devient acrobatique et peut paralyser des mises à jour pendant des mois.
Nix inverse cette logique :
- À la compilation, le compilateur est enveloppé pour inscrire en dur dans chaque binaire le chemin absolu de sa propre version de glibc dans
/nix/store(PT_INTERP). - Il inscrit également dans son en-tête la liste exhaustive des chemins du magasin où trouver ses dépendances (RPATH / RUNPATH).
Chaque programme dispose ainsi de son propre chargeur et de son propre graphe de dépendances, hermétique et isolé du reste du système. Deux programmes utilisant des versions incompatibles de la même bibliothèque s’exécutent côte à côte sans jamais se parasiter.
Pour les commandes de tous les jours, la variable $PATH pointe simplement vers un profil de liens symboliques (/run/current-system/sw/bin pour le système ou ~/.nix-profile/bin pour l’utilisateur) qui renvoie vers ces binaires du magasin.
Exécuter des binaires précompilés tiers
Puisque les répertoires standards sont absents, un binaire générique téléchargé sur Internet échoue au lancement dès lors qu’il utilise du linkage dynamique : le noyau cherche /lib64/ld-linux-x86-64.so.2, ne le trouve pas et renvoie l’erreur trompeuse No such file or directory. Même s’il démarrait, il ne trouverait aucune bibliothèque dans /usr/lib.
Pour faire tourner ces logiciels fermés ou tiers, il faut leur fournir un chargeur et déclarer explicitement les bibliothèques à mettre à leur disposition :
nix-ld(résolution globale) : installe un shim léger dans/lib64/ld-linux-x86-64.so.2. Dans la configuration NixOS (programs.nix-ld.libraries), on liste les bibliothèques système communes (zlib,openssl, etc.). Le relai intercepte le lancement du binaire tiers et le connecte automatiquement à cette sélection.patchelf(adaptation par paquet) : un utilitaire qui opère une chirurgie directe sur l’en-tête du binaire ELF. Il remplace le chargeur dynamique par celui de la glibc du magasin et inscrit dans le RPATH les paquets listés dans la recette Nix. Dans un paquet, le crochetautoPatchelfHookanalyse les besoins du binaire et automatise ce câblage à partir des dépendances déclarées.buildFHSEnv(isolation en bac à sable) : utilise les espaces de noms du noyau Linux (namespaces, via Bubblewrap) pour exécuter l’application dans un environnement éphémère. On lui déclare une liste de paquets (targetPkgs), et l’outil monte une arborescence FHS standard virtuelle (/bin,/lib,/usr/lib) composée de liens symboliques vers le magasin Nix.
Configuration déclarative d’une machine
Sur NixOS, l’état complet du système est consigné dans un fichier déclaratif. On ne tape plus de commandes pour configurer un service : on décrit le résultat souhaité.
{ config, pkgs, ... }: {
networking.hostName = "serveur-atelier";
time.timeZone = "Europe/Paris";
# Activation d'un service système
services.openssh.enable = true;
# Déclaration d'un compte utilisateur
users.users.alice = {
isNormalUser = true;
extraGroups = [ "wheel" ];
};
# Paquets mis à disposition globale
environment.systemPackages = with pkgs; [
curl
htop
git
];
}
Si une ligne est retirée de ce fichier, le paquet ou le service correspondant disparaît de la machine dès la bascule suivante. Le système reflète exactement ce qui est écrit, sans résidus d’anciennes installations.
Puisque rien n’est jamais écrasé, le magasin de paquets grossit au fil des évolutions, et ce jusqu’à ce que votre disque dur soit plein.
Pour pallier cela, un ramasse-miettes (garbage collector) automatique se configure en quelques lignes pour purger les générations antérieures à trente jours :
nix.gc = {
automatic = true;
dates = "weekly";
options = "--delete-older-than 30d";
};
Le compromis est matériel : supprimer les générations de plus de trente jours retire aussi la possibilité d’y revenir. Le délai se règle selon la durée pendant laquelle on veut conserver la faculté de faire machine arrière.
L’éléphant dans la pièce : la gestion des données
NixOS garantit la reproductibilité du système et des applications, mais ne versionne pas les données applicatives.
Prenons le cas concret d’un déploiement le vendredi soir : une application migre sa base de données vers un nouveau schéma ou convertit des documents stockés sur le disque. Si un dysfonctionnement apparaît le samedi, revenir à la version logicielle précédente via NixOS ne prend qu’une commande.
Mais l’ancien binaire sera incapable de lire les données déjà migrées par la nouvelle version.
Revenir en arrière au niveau du système d’exploitation ne sert à rien si les données ont subi une modification irréversible.
La réponse pragmatique consiste à associer NixOS à un système de fichiers avec copie sur écriture (Copy-on-Write), comme Btrfs ou ZFS. Juste avant la bascule du système, un instantané (snapshot) des sous-volumes de données est déclenché.
Btrfs prend un instantané immédiat, sans copier les données au départ. Grâce à la copie sur écriture, seules les modifications ultérieures consomment de l’espace, le reste est partagé. Revenir en arrière consiste à changer d’instantané, et l’isolation passe par des sous-volumes distincts.
Une précaution matérielle s’impose toutefois : un instantané bloc pris à chaud sur un moteur de base de données actif (comme PostgreSQL) fige les fichiers tels quels. Sans gel préalable des écritures (quiesce) ou déclenchement d’un point de contrôle (checkpoint/WAL), l’opération équivaut à un arrêt brutal et demandera un rejeu du journal des transactions au redémarrage.
En cas d’incident, on restaure simultanément la génération NixOS et l’instantané Btrfs : le code et les données retrouvent rigoureusement leur état d’origine. C’est l’illustration matérielle du principe selon lequel sauvegarder n’est pas restaurer (article accessible) : seule une reconstruction mécanique et testée garantit la reprise d’activité.
Flakes : modularité et verrouillage au commit près
Historiquement, Nix souffrait d’un angle mort : il manquait d’un format standardisé pour gérer ses dépendances externes. Deux développeurs évaluant un même fichier pouvaient obtenir deux machines différentes si leurs canaux de paquets (channels) locaux n’avaient pas été synchronisés le même jour.
Le mécanisme des Flakes apporte enfin à Nix ce que package.json est à JavaScript ou Cargo.toml à Rust : un système de paquets et de modularité universel. Il permet d’importer des briques de code tierces ou de mettre à disposition des recettes réutilisables aussi simplement qu’une bibliothèque dans n’importe quel langage.
Un fichier flake.nix normalise les entrées et les sorties de n’importe quel projet :
- Les entrées (inputs) : les dépendances et briques externes dont on a besoin (le catalogue de recettes
nixpkgs, un module système écrit par un collègue, un outil partagé). - Les sorties (outputs) : ce que le projet produit et expose au reste du monde (un exécutable, un environnement de travail, une image de conteneur, ou la configuration complète d’un serveur).
- Le fichier de verrouillage (
flake.lock) : fige chaque entrée au commit et à la somme de contrôle près, garantissant un déterminisme absolu d’une machine à l’autre.
Ce cadre unique permet par exemple de piloter un parc complet de machines (serveurs d’atelier, postes de développement) depuis un seul dépôt Git :
# Construire la configuration d'un portable sans l'activer
nixos-rebuild build --flake .#portable
# Construire et appliquer la configuration du serveur sur la machine courante
nixos-rebuild switch --flake .#serveur --sudo
# Déployer et activer la configuration du serveur d'atelier à distance
nixos-rebuild switch --flake .#atelier --target-host root@atelier
Le nom après le # sélectionne la cible parmi les sorties du flake (nixosConfigurations). Mettre à jour son parc revient à lancer nix flake update pour actualiser le fichier verrou, puis à appliquer les bascules machine par machine.
Un flake permet aussi de composer finement ses dépendances : on peut importer simultanément la branche stable et la branche instable de nixpkgs (pour piocher ponctuellement un paquet récent via pkgs.unstable), ou forcer une brique tierce comme home-manager à réutiliser notre propre version de nixpkgs via la directive follows, évitant de dupliquer les téléchargements.
Au quotidien, un réflexe s’impose : en mode flake, Nix n’évalue strictement que les fichiers indexés par Git. Tout fichier non suivi reste invisible pour la construction, d’où le passage par git add. Les commandes unifiées nix build, nix run, nix develop et nix shell exploitent ensuite directement ces sorties standardisées.
Des briques prêtes à l’emploi pour la production
Cette facilité à importer des modules réutilisables a donné naissance à tout un écosystème de briques spécialisées qu’il suffit de brancher dans ses entrées (inputs) :
home-manager: applique la même logique déclarative à la session utilisateur (fichiers de configuration, raccourcis, outils du terminal).deploy-rs: outil de déploiement à distance sans agent lourd. En cas d’anomalie réseau ou de coupure SSH après mise à jour, il détecte automatiquement la rupture et fait marche arrière vers la configuration précédente sans intervention humaine.sops-nix: gestion des secrets chiffrés directement dans le dépôt Git (via l’outil SOPS et des clés GPG ou age), déchiffrés en mémoire vive au démarrage sans laisser de traces sur le disque. Il existe d’autres flakes aux fonctionnalités similaires.pin-oci.nix, dont je suis l’auteur : comble un vide majeur dans la gestion des conteneurs sous Nix. Déclarer une image par son étiquette (tag commelatestou16-alpine) réintroduit une dépendance mutable : l’image peut changer sur le registre sans prévenir. L’outil résout les étiquettes en amont et fige leurs empreintes cryptographiques (digests) dans un fichierpin-oci.lock, étendant la reproductibilité stricte de Nix aux conteneurs OCI (Docker et Podman).llm-agents.nix: distribution d’outils et d’agents d’intelligence artificielle en ligne de commande. Dans un écosystème qui évolue chaque jour, les paquets denixpkgs(même sur le canal unstable) accusent souvent un temps de retard. Ce flake actualise automatiquement ses recettes deux fois par jour via un pipeline GitHub Actions directement depuis les dépôts amont des éditeurs, garantissant l’accès immédiat aux dernières versions sans sacrifier la reproductibilité.
Docker et NixOS : complémentarité et passerelles
Une question revient fréquemment chez les équipes techniques : Nix remplace-t-il Docker ?
La réponse est non. Docker et NixOS répondent à des besoins différents et fonctionnent très bien ensemble, selon qu’on consomme des conteneurs ou qu’on en produit.
Consommer des images existantes
Adopter NixOS ne demande pas de réécrire tous ses services en modules Nix du jour au lendemain.
- NixOS pilote les conteneurs : l’option
virtualisation.oci-containerspermet de déclarer des conteneurs Docker ou Podman directement dans le fichier de configuration de l’hôte. Chaque conteneur devient une unité systemd versionnée et intégrée à la machine. - Podman de préférence : sans démon central, le conteneur s’intègre directement aux groupes de contrôle (cgroups) de systemd et devient un service système à part entière. Avec Docker, deux gestionnaires d’état cohabitent (systemd et
dockerd), l’unité se contentant d’appelerdocker run. compose2nix: cet outil (disponible surnixpkgs) convertit automatiquement un fichierdocker-compose.ymlexistant en configuration NixOS native (conteneurs, réseaux, volumes), évitant toute réécriture manuelle lors d’une phase de transition.- L’image Docker officielle : la fondation NixOS fournit une image
docker.io/nixos/nixqui permet d’utiliser le gestionnaire de paquets au sein de pipelines d’intégration continue classiques.
Produire des images avec Nix
Un Dockerfile classique réintroduit la mutation. Avec une instruction comme RUN apt-get update, l’image construite aujourd’hui n’est pas celle qui sortira dans trois mois ; les couches sont impératives et leur cache n’est pas déterministe ; enfin, l’image embarque un système de base et un gestionnaire de paquets dont l’application finale n’a pas l’usage.
Nix remplace le Dockerfile par une fonction pure qui produit directement une image standardisée (OCI), comme n’importe quelle dérivation, sans démon Docker actif ni privilèges root. En intégration continue, aucune socket Docker n’est exposée et aucune élévation de privilèges n’est requise.
dockerTools.buildLayeredImage(fourni parnixpkgs) : analyse le graphe des dépendances du magasin et les répartit en couches stables, pour maximiser la réutilisation du cache au téléchargement et à l’envoi.nix2container: évite l’archive intermédiaire sur disque et envoie les couches directement du magasin vers le registre. Les images de ce site sont construites ainsi.devenv container: conteneurise un environnement de développement en une commande, sur le même principe.
L’image finale ne contient que la fermeture (closure) du magasin de l’application, c’est-à-dire les stricts binaires qu’elle référence : pas de curl, de bash ni de compilateur oublié. La surface d’attaque diminue d’autant, et l’image se reconstruit à l’identique à partir des mêmes entrées verrouillées.
Par où commencer : l’adoption progressive avec devenv.sh
Passer un parc de serveurs ou des postes de travail sous NixOS du jour au lendemain est rarement réaliste. En revanche, l’immuabilité peut s’adopter dès demain sur un projet précis, sans changer de système d’exploitation, que ce soit sur Linux, macOS (nix-darwin), ou encore Windows (via WSL 2).
L’outil devenv.sh s’appuie sur Nix pour créer des environnements de développement isolés, décrits dans un simple fichier devenv.nix :
{ config, pkgs, ... }:
let
dbName = "mon_projet";
in {
packages = with pkgs; [ gcc git openssl ];
# Charge le .env (priorité basse : `env` ci-dessous l'emporte)
dotenv.enable = true;
languages.javascript = {
enable = true;
nodejs.enable = true;
npm = {
enable = true;
};
};
# Service de test local Mailpit
services.mailpit.enable = true;
env = {
DATABASE_URL = "postgres://postgres@localhost:${toString config.services.postgres.port}/${dbName}";
SMTP_HOST = "127.0.0.1";
};
# Base PostgreSQL locale avec extension vectorielle
services.postgres = {
enable = true;
port = 5433;
extensions = extensions: [
extensions.pgvector
];
initialDatabases = [{ name = dbName; }];
};
}
Les données des services locaux (comme PostgreSQL) sont stockées dans le répertoire local .devenv, au même niveau que votre devenv.nix, évitant d’encombrer le système global ou de risquer des conflits de ports avec d’autres projets.
L’exécution repose sur deux commandes simples :
devenv shell(ou automatiquement dès lecdgrâce àdirenv) pour entrer dans l’environnement avec les compilateurs et dépendances verrouillés ;devenv uppour lancer les services locaux d’arrière-plan.
Avec dotenv.enable, le fichier .env fournit des valeurs par défaut que l’attribut env de devenv.nix écrase : le fichier versionné l’emporte sur le fichier local. Côté programme, il reste à vérifier l’ordre de chargement des variables (les variables d’environnement devraient prévaloir sur le fichier .env), car un ordre inverse reste une source classique de comportements aussi sogres que grenus.
Le fichier devenv.lock assure que chaque développeur de l’équipe partage rigoureusement les mêmes binaires. L’arrivée d’une personne tient alors en git clone, puis devenv shell.
De la mutation à l’immuabilité
L’approche repose sur trois piliers indissociables :
- Le système déclaratif : la configuration devient du code source versionné.
- L’immuabilité : la bascule entre versions est atomique, sans écrasement en place.
- La reproductibilité : les dépendances et empreintes sont verrouillées au commit près.
Ce n’est pas un changement d’outil, mais un changement de posture : cesser de subir l’état imprévisible d’un système pour en reprendre la maîtrise complète.
Questions fréquentes
Que se passe-t-il si un paquet n’existe pas dans nixpkgs ?
Il est possible d’écrire sa propre dérivation en quelques lignes dans le dépôt du projet. Nix permet également d’intégrer directement un dépôt Git distant comme entrée via les Flakes, ou d’encapsuler un binaire externe via patchelf ou buildFHSEnv.
La courbe d’apprentissage n’est-elle pas trop abrupte ?
Oui, pour un système complet. Le langage Nix et la disparition du standard FHS imposent un changement d’habitudes significatif. C’est pourquoi commencer par devenv.sh sur un projet applicatif permet d’en récolter les bénéfices immédiats (reproductibilité des postes, zéro conflit de versions) sans subir la complexité de gestion du système hôte.
NixOS est-il réservé aux serveurs informatiques ?
Non, absolument pas. Si l’immuabilité prend tout son sens sur des serveurs de production, NixOS propulse tout aussi bien des postes de bureautique administrative pour des équipes de gestion, des ordinateurs portables de développement, ou même ma propre machine de jeu au quotidien (avec Steam, pilotes graphiques NVIDIA propriétaires et lanceurs isolés via buildFHSEnv sans jamais polluer le système hôte).
Pourquoi préférer NixOS à un gestionnaire de configuration comme Ansible ou Puppet ?
Ansible et Puppet appliquent des mutations successives sur une machine existante. Même si ces outils visent l’idempotence, ils ne garantissent ni la convergence absolue (si un fichier est modifié manuellement à côté, la dérive s’installe), ni le retour arrière atomique si le playbook plante à mi-parcours. NixOS ne modifie rien sur place : il compile un état intégral et bascule de façon atomique. Deux machines partageant la même déclaration sont rigoureusement jumelles.
Peut-on administrer un parc de postes de travail sans Active Directory ?
Oui. Pour la gestion d’une flotte de postes, le modèle déclaratif de NixOS remplace avantageusement la lourdeur d’un annuaire Active Directory et de ses stratégies de groupe (GPO) : comptes utilisateurs, règles de sécurité, logiciels autorisés et profils se pilotent depuis un simple dépôt Git versionné.
L’État français ne s’y est d’ailleurs pas trompé : la DINUM (Direction interministérielle du numérique) s’appuie directement sur NixOS à travers des initiatives comme les projets Sécurix et Bureautix pour concevoir des postes de travail souverains, durcis et reproductibles pour les agents publics.
À retenir
- La mutation traditionnelle traite la préparation et l’activation en même temps, rendant les mises à jour fragiles et les retours arrière incertains.
- L’immuabilité prépare le nouvel état intégralement à côté de l’existant, puis bascule de manière atomique.
- Nix et NixOS transforment la configuration et les paquets en fonctions pures, garantissant des constructions reproductibles à partir d’entrées verrouillées.
- L’adoption la plus pragmatique commence au niveau du projet de développement grâce à
devenv.sh, avant d’envisager le système d’exploitation.
C’PRAG accompagne les entreprises dans la fiabilisation et la reprise en main de leurs infrastructures logicielles et systèmes.
L’approche pragmatique
- Diagnostic opérationnel de la reproductibilité des environnements.
- Cartographie des dépendances invisibles et points de divergence.
- Isolation des briques d’exécution et mise sous contrôle des versions.
- Mise en place de bascules atomiques et procédures de retour arrière vérifiées.
En une à deux journées, sans interrompre la production.
Réservez un échange préalable de 15 minutes pour en parler : un environnement de développement qui met une demi-journée à s’installer est le premier signe d’un système qui a perdu sa reproductibilité.
Pour aller plus loin
- Nix Map (Vimjoyer) : cartographie visuelle et interactive pour vous aider à explorer l’écosystème Nix selon vos besoins.
- search.nixos.org : moteur de recherche officiel des paquets
nixpkgset des options de configuration NixOS. - nix.dev : guides d’apprentissage officiels et tutoriels pratiques de la fondation Nix.
- noogle.dev : moteur de recherche dédié aux fonctions et à la bibliothèque standard du langage Nix.
Sources
- Corentin VÉROT VASSAL. Conférence BYOD Systèmes immuables : fiabilité et reproductibilité, La Brasserie du Digital (Le Puy-en-Velay, 13 octobre 2026). Télécharger le support (PDF).
- Dolstra, Eelco. The Purely Functional Software Deployment Model (PhD Thesis, 2006).
- Repology - Statistiques des dépôts de paquets (octobre 2026).
- Documentation officielle NixOS et nixpkgs.
- Projet devenv.sh - Fast, Declarative, Reproducible Developer Environments.