Code

Majdi Toumi

Lalallm

Ou comment j'ai arrêté de perdre du temps à configurer mes ordinateurs.

Prélude

J'ai trois Macs : un iMac à la maison, un Mac Mini comme station secondaire et un MacBook pour la mobilité. Pendant des années, au quotidien, j'installais un outil sur une machine, oubliais de le faire sur l'autre et me retrouvais à chercher pourquoi la commande ou le logiciel n'existe pas alors que je l'utilise tous les jours sur l'autre machine.

Côté programmation, une version de Node ou Go différente sur chaque machine, un environnement Python configuré dans l'un mais pas pareil sur les autres.

Tu connais, on connait, c'est relou.

Un jour j'ai craqué. J'ai décidé que ce problème n'existerait plus.

Un fichier pour les gouverner tous

Avant de te montrer comment je fais, il faut poser deux bases : Nix et Flakes.

Nix, la base

J'utilise Nix (ou plus précisément Lix) qui n'est pas juste un gestionnaire de paquets. C'est une manière différente de penser la configuration d'une machine.

Au lieu de cliquer partout, d'installer des outils à la main, puis d'oublier ce que tu as fait, tu décris ton système dans un ou plusieurs fichiers texte. Ces fichiers disent précisément ce que tu veux sur ta machine :

Ensuite, Nix se charge de rendre la machine conforme à cette description. Toujours de la même manière. De façon reproductible. Pas besoin de se soucier de comment tout ça doit être assemblé.

Si le fichier n'a pas changé, la machine non plus.

Sur macOS, cette approche se fait via un utilitaire appelé nix-darwin, qui est une couche qui permet à Nix de piloter :

En pratique, ça veut dire une chose simple : ton Mac devient le résultat d'un fichier, pas d'une suite d'actions oubliées.

Flakes, la colle

Les Flakes, c'est la version moderne et propre de Nix. Sans entrer dans les détails techniques, elles apportent surtout : une structure claire, des dépendances figées et la possibilité de gérer plusieurs machines depuis un seul point central.

C'est ce qui permet d'avoir :

Toutes ces machines seront bien évidemment physiquement différentes, mais identiques du point de vue de l'environnement de travail.

Hands-on

Ok, maintenant que tu as les bases, je peux te montrer ce que j'ai fais.

J'ai un repo dotfiles sur Git regroupant l'ensemble de ma configuration : terminal, git, raycast, gcloud, etc. J'y ai ajouté un seul fichier flake.nix avec mes 3 machines qui pointent dessus.

dotfiles/nix-darwin main [$] on gcp (confiture-prd)
 ls
flake.lock flake.nix

Le fichier lock est généré par Nix avec les versions exactes des paquets installés.

Ce que mon fichier Flake contient

Mes outils CLI — tout ce que j'utilise au quotidien, exemple :

environment.systemPackages = [
  pkgs.jq
  pkgs.starship
  pkgs.grpcurl
  pkgs.httpie
];

Mes packages Homebrew – CLI et applications, oui oui, même ça, exemple :

homebrew = {
  brews = [
    "bun"
    "gh"
    "go"
    "node"
    "ollama"
    "python"
    "uv"
  ];

  casks = [
    "docker-desktop"
    "ghostty"
    "cursor"
    "raycast"
    "1password"
  ];

  onActivation.cleanup = "zap";
};

Le zap c'est un peu vicieux mais j'aime bien : il désinstalle tout ce qui n'est pas dans ma liste. L'environnement de chaque machine reste synchronisé, propre et sans effort. Ça fait du bien.

Les préférences macOS :

system.defaults = {
  dock.autohide = true;
  finder.AppleShowAllExtensions = true;
  NSGlobalDomain.KeyRepeat = 1;
  NSGlobalDomain.InitialKeyRepeat = 10;
};

Du coup plus besoin d'aller tout configurer 10x dans les menus comme avoir un clavier qui se répète vite et pareil sur toutes mes machines.

Mon workflow maintenant

Depuis maintenant 1 ans, dès que je veux veux un nouvel outil, j'ajoute simplement une ligne et je rebuild mon système nix :

darwin-rebuild switch --flake .#iMac

. est le chemin vers mon fichier de configuration flake.nix et ensuite je précise le nom de la machine.

Je fais pareil sur les autres machines quand je les utilise et biiim, elles convergent toutes vers la même configuration.

Si demain j'ai une nouvelle machine ?
J'ai juste à cloner mon repo, à lancer la commande et prendre un café.

Ce que j'ai appris

Clairement, je ne reviendrai pas en arrière et je suis trop content de cette configuration. Je peux aujourd'hui coder et utiliser n'importe quel outil sur n'importe laquelle de mes machines. C'est la même configuration.

Pour finir ce post, mon petit feedback à propos de Nix ↓

L'ordre

Un point clé de Nix, et la raison pour laquelle tout ça tient dans le temps, c'est le modèle déclaratif ; Je ne dis pas à ma machine comment installer Node, Go ou Docker. Je lui dis ce que je veux.

La différence est subtile mais fondamentale :

Nix se débrouille pour y arriver. Le résultat est parfaitement conforme à la déclaration :

Si la déclaration est la même, le résultat l'est aussi. C'est cette idée qui me permet de dormir tranquille avec plusieurs machines.

Le chaos

Soyons honnêtes. Nix n'est pas simple.
La syntaxe peut être déroutante, les erreurs sont parfois cryptiques et au début, tu ne sais jamais si le problème vient de toi, du paquet, ou de Nix lui-même.

J'ai déjà cassé des trucs mais il m'est jamais arrivé de bloquer une soirée entière pour une virgule mal placée ou pour comprendre pourquoi un package cassait à cause de ma locale. Merci le vibe coding.

Aussi, autre points importants, dans ma configuration, je mélange les sources de Nix et Homebrew. Dans l'idéal, tout passe par Nix surtout que j'envisage à moyen terme de repasser sous Linux.

Dans la réalité, ce n'est pas toujours souhaitable.

La raison principale est le rythme de publication des software.
Nix a tendance à être plus lent que Homebrew car il privilégie la stabilité et la reproductibilité des versions qui arrivent donc après avoir été testées, intégrées, validées, etc.

C'est très bien pour un système mais c'est parfois frustrant pour des outils qui évoluent vite ou qu'on a besoin lors de développement.

À l'inverse, Homebrew suit de très près les sorties upstream. Quand une nouvelle version de Node par exemple ou un outil CLI populaire sort, elle arrive souvent le jour même.

Du coup, je fais un choix pragmatique :

Ce n'est pas une hérésie. C'est un compromis assumé car pour moi l'important, ce n'est pas que tout passe par le même outil mais que tout soit déclaré au même endroit.

A+ ✌️