Aller au contenu

Justfile : l'outil d'automatisation simple qui remplace mes scripts Bash

J'ai des fichiers Justfile dans tous mes projets : sites web, agents IA, outils Rust, skills pour agents IA. Retour d'expérience sur l'outil d'automatisation le plus simple que j'ai trouvé pour remplacer les scripts bash éparpillés et les Makefile illisibles.

Détournement d'une scène du film dîner de cons - Pierre : « Il l'appelle Just, l'outil », François : « Ah bon, il n'a pas de nom »
Justfile : l'automatisation simple et efficace.

Un fichier, des recettes lisibles, et une migration depuis Make en moins d'une journée. Just est un outil d'automatisation qui remplace avantageusement les scripts bash éparpillés et les Makefile difficiles à maintenir. Voici pourquoi il est devenu mon outil par défaut sur tous mes projets.

Le principe

Un fichier Justfile à la racine du projet, des recettes lisibles, et just <recette> dans le terminal. Pas de magie, pas de syntaxe ésotérique. Quand un nouveau collègue arrive sur un projet, just --list lui montre tout ce qu'il peut faire :

# Installer les dépendances
install:
    npm install

# Lancer le serveur de développement
dev:
    npm run dev

# Lancer les tests
test:
    npm run test

# Tout préparer d'un coup
setup: install dev
Sortie de just --list : les recettes disponibles s'affichent avec leur description

Les fonctionnalités qui comptent vraiment

La documentation officielle de Just couvre la syntaxe en détail. Place aux fonctionnalités que j'utilise le plus au quotidien.

Groupes de recettes

Sur un projet avec beaucoup de recettes, just --list peut devenir illisible. C'est là que les groupes changent la donne :

# Installer les dépendances
[group('setup')]
install:
    uv sync --active

# Lancer l'API
[group('run')]
api:
    uv run uvicorn app.main:app --reload

# Formater le code
[group('quality')]
format:
    uv tool run ruff format src/

# Linter le code
[group('quality')]
lint:
    uv tool run ruff check src/

# Lancer les tests avec couverture
[group('quality')]
test:
    uv run pytest --cov=src/app --cov-report=term-missing

Résultat : les recettes s'affichent par catégorie, et on s'y retrouve immédiatement.

Sortie de just --list avec groupes : les recettes sont organisées par catégorie (quality, run, setup)

Imports modulaires

Quand un projet grossit, un seul Justfile devient un monolithe. Just permet de découper en fichiers thématiques. Sur mon projet agent-skills, le Justfile racine ne fait que rassembler :

set quiet := true

import 'just/quality.just'
import 'just/skills.just'
import 'just/documentation.just'
import 'just/development.just'
import 'just/python.just'

# Afficher les recettes disponibles
default:
    just --list

Chaque fichier gère son domaine : quality.just contient le linting et la validation, skills.just la création et le test de skills. On peut travailler sur un domaine sans toucher aux autres.

Recettes privées et prérequis

Je préfixe mes recettes utilitaires par _ pour les masquer de just --list, tout en les gardant comme dépendances. Je m'en sers systématiquement pour vérifier les prérequis :

# Vérifier qu'UV est disponible
_check-uv:
    #!/usr/bin/env bash
    if ! command -v uv &> /dev/null; then
        echo "ERROR: UV est requis mais non installé."
        echo "Installez UV depuis : https://docs.astral.sh/uv/"
        exit 1
    fi

# Installer les dépendances
[group('setup')]
install: _check-uv
    uv sync --active

L'utilisateur ne voit que install dans la liste, mais la vérification se fait automatiquement.

Compatibilité multiplateforme

Just est compatible Linux, macOS et Windows. J'utilise la fonction os_family() pour adapter mes recettes au système :

python_dir := if os_family() == "windows" { "./.venv/Scripts" } else { "./.venv/bin" }
python := python_dir + if os_family() == "windows" { "/python.exe" } else { "/python3" }

# Installer l'environnement de développement
bootstrap:
    if test ! -e .venv; then python3.13 -m venv .venv; fi
    {{ python }} -m pip install --upgrade pip wheel pip-tools

Exemple complet multiplateforme dans la documentation officielle.

Rendre les fichiers Justfile portables

Quand un Justfile est importé depuis un autre répertoire, les chemins relatifs cassent. J'utilise source_directory() pour résoudre ce problème : la fonction renvoie toujours le répertoire du Justfile lui-même :

# Ce Justfile fonctionne correctement même importé depuis ailleurs
[group('Documentation')]
explore:
    cd {{ source_directory() }} && docker run -it --rm -p 8080:8080 \
      -v {{ source_directory() }}:/usr/local/structurizr structurizr/lite

C'est ce qui rend possible le pattern « Justfile réutilisable » que j'utilise pour la documentation d'architecture.

Just sur le terrain

La vraie valeur de Just se révèle dans des cas d'usage concrets. Voici deux exemples tirés de projets réels.

Un workflow complet pour un site web

Sur le projet W.R.A.A.S., le Justfile orchestre tout le cycle de développement d'un site statique : build avec cache-busting, linting custom (HTML, CSS, JS), tests Playwright et audits Lighthouse.

src := "site"
out := "_site"
port := "8000"

# Serveur de développement local
[group('dev')]
dev:
    python3 dev-server.py {{ port }} {{ src }}

# Build avec cache-busting automatique
[group('build')]
build: clean
    mkdir -p {{ out }}
    cp -r {{ src }}/* {{ out }}/
    @just cache-bust

# Ajouter des hash de contenu aux assets statiques
[group('build')]
cache-bust:
    #!/usr/bin/env bash
    set -euo pipefail
    css_hash=$(sha256sum {{ out }}/style.css | cut -c1-8)
    js_hash=$(sha256sum {{ out }}/script.js | cut -c1-8)
    for html_file in $(find {{ out }} -name '*.html'); do
        sed -i "s|/style\.css\"|/style.css?v=${css_hash}\"|g" "$html_file"
        sed -i "s|/script\.js\"|/script.js?v=${js_hash}\"|g" "$html_file"
    done

# Tous les checks (lint + build + tests)
[group('ci')]
check: lint lint-docs build test
    @echo "All checks passed"

# Audits Lighthouse sur toutes les pages
[group('test')]
lighthouse: build
    #!/usr/bin/env bash
    # ... démarre un serveur local, teste chaque page,
    # vérifie que les scores sont >= 90

Ce qui est intéressant ici, c'est que Just remplace à la fois un script de build, un linter maison et un runner de CI, le tout lisible d'un coup d'œil avec just --list.

Sur ce projet comme sur les autres, j'ajoute systématiquement une recette pre-commit qui chaîne formatage, linting et tests. Un just pre-commit avant de committer et on est serein. C'est aussi ce que la CI exécute : même commande, même résultat.

Sortie de just pre-commit : formatage, linting et tests passent avec 94,2 % de couverture

Architecture as Code avec des agents IA

Chez la Compagnie Hébus, j'ai mis en place un pattern pour documenter l'architecture de chaque projet avec Structurizr (modèle C4). Le Justfile standardisé vit dans docs/architecture/ et offre un workflow complet :

set quiet := true

# Visualiser l'architecture dans le navigateur
[group('Documentation')]
explore:
    cd {{ source_directory() }} && docker run -it --rm -p 8080:8080 \
      -v {{ source_directory() }}:/usr/local/structurizr structurizr/lite

# Valider la syntaxe du workspace.dsl
[group('Development')]
validate:
    cd {{ source_directory() }} && docker run --rm \
      -v {{ source_directory() }}:/usr/local/structurizr \
      structurizr/cli validate -workspace workspace.dsl

# Exporter les vues en Mermaid + SVG
[group('Delivery')]
export-mermaid:
    #!/usr/bin/env bash
    cd {{ source_directory() }} \
      && mkdir -p diagrams && rm -f diagrams/* \
      && docker run --rm \
        -v {{ source_directory() }}:/usr/local/structurizr \
        structurizr/cli export -workspace workspace.dsl \
        --format mermaid -output diagrams \
      && find * -name "*.mmd" | xargs -I {} -n 1 mmdc -i {} -o {}.svg

Ce Justfile est importé dans le Justfile principal de chaque projet :

import 'docs/architecture/justfile'

Grâce à source_directory(), les commandes Docker montent toujours le bon répertoire, quel que soit l'endroit d'où on les appelle. J'ai ensuite intégré ce Justfile dans un skill d'agent IA (j'utilise Claude Code, mais le format agent skill est compatible avec d'autres agents) : quand l'agent génère un workspace.dsl, il peut immédiatement le valider et l'exporter en lançant just validate et just export-mermaid.

Diagramme d'architecture C4 généré par just export-mermaid : containers, API, base de données et systèmes externes

Et Make dans tout ça ?

La question revient systématiquement. Voici ce qui m'a fait basculer :

Caractéristique Make Just
Syntaxe Complexe, sensible aux tabs Simple et intuitive
Objectif Compilation de projets C/C++ Automatisation générale
Compatibilité POSIX, variations selon l'OS Multiplateforme cohérent
Courbe d'apprentissage Raide Douce
Gestion des dépendances Basée sur les fichiers Basée sur les recettes
Messages d'erreur Parfois cryptiques Clairs et explicites
Disponibilité Préinstallé quasi partout À installer

Make a des avantages réels : il est déjà là sur la plupart des machines, et pour les projets C/C++ avec des dépendances de compilation il reste le choix naturel. Pour tout le reste (projets web, scripts, DevOps, agents IA), Just me semble plus adapté. Et surtout, quand je partage un Justfile avec un collègue qui n'a jamais utilisé l'outil, il comprend immédiatement ce que font les recettes. Ce qui est plus compliqué avec un Makefile.

Conclusion

Mon point de départ, c'était une dizaine de Makefile imbriqués que plus personne, ou presque, ne savait maintenir. J'ai cherché une alternative, découvert Just, et migré l'ensemble en moins d'une journée, présentation à l'équipe incluse. Depuis, j'en ai dans tous mes dépôts : des sites statiques aux outils en Rust, en passant par des projets géospatiaux et des skills pour agents IA.

Ce qui m'a convaincu, ce n'est pas une fonctionnalité en particulier, c'est l'accumulation : la syntaxe lisible, les imports modulaires, les groupes, la portabilité. Et le vrai test, c'est l'onboarding. Quand un nouveau développeur arrive sur un projet et que just --list lui montre exactement ce qu'il peut faire, sans lire un README de 200 lignes, l'outil a rempli sa mission.

Pour aller plus loin

Dernier