Qu’est-ce que Turborepo ?
Turborepo est un système de build haute performance pour les monorepos JavaScript. Il exécute des tâches sur l’ensemble des packages de votre dépôt, respecte l’ordre des dépendances entre eux et met les résultats en cache afin que le travail non modifié ne soit jamais répété.
Un monorepo sans système de build devient rapidement pénible à gérer. Lancer build et test manuellement dans chaque package est lent, et un script naïf relance tout même lorsqu’un seul package a été modifié. Turborepo résout ces deux problèmes : un pipeline de tâches déclaratif gère l’ordonnancement, et le hachage basé sur le contenu rend les tâches inchangées pratiquement instantanées.
Le pipeline de tâches
Le pipeline se trouve dans turbo.json. Chaque tâche déclare ses dépendances et ses sorties.
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}
dependsOn avec un accent circonflexe (^build) signifie « build mes dépendances d’abord ». Sans l’accent, cela fait référence à une tâche dans le même package. outputs indique à Turborepo quoi mettre en cache, et cache: false exclut une tâche comme dev car elle s’exécute indéfiniment.
Exécution des tâches
Une seule commande permet d’exécuter une tâche sur l’ensemble du dépôt, dans le bon ordre et en parallèle lorsque c’est possible.
turbo run build
turbo run test lint
turbo run dev --filter=web
Turborepo construit un graphe à partir de dependsOn, exécute les tâches indépendantes simultanément et met en file d’attente celles qui présentent des dépendances. Le résultat est le planning le plus rapide possible tout en respectant les contraintes entre les packages.
Mise en cache
La mise en cache est la fonctionnalité qui transforme radicalement l’expérience d’un monorepo. Pour chaque tâche, Turborepo calcule le hash des entrées — fichiers sources, dépendances, variables d’environnement et configuration — et stocke les sorties ainsi que les logs associés à ce hash.
Lors de l’exécution suivante, si le hash n’a pas changé, la tâche est ignorée et ses sorties sont restaurées depuis le cache. Les logs sont également rejoués, sehingga le résultat semble identique sans que le travail ne soit effectué. Avec un cache “chaud”, un turbo run build complet sur des dizaines de packages peut se terminer en quelques secondes.
Mise en cache distante
Un cache local n’est utile que pour une seule machine. La mise en cache distante (remote caching) permet de partager le cache entre toute l’équipe et la CI.
- Un développeur build un package ; le résultat est téléversé.
- Un autre développeur récupère le même commit et restaure le résultat instantanément.
- La CI restaure les mêmes artefacts, évitant ainsi de refaire un travail déjà effectué ailleurs.
Cela transforme le cache en une ressource partagée et constitue souvent le gain de performance le plus important pour la CI d’un monorepo. Vercel propose un cache distant hébergé, et des options auto-hébergées existent pour les équipes qui en ont besoin.
Filtrage
Les monorepos de grande taille ont rarement besoin d’exécuter chaque tâche. Le filtrage permet de cibler un sous-ensemble de packages.
# only packages affected by changes since main
turbo run test --filter="...[origin/main]"
# one package and its dependencies
turbo run build --filter=web...
# only packages that depend on @repo/ui
turbo run build --filter=...@repo/ui
La syntaxe [origin/main] demande à Turborepo de calculer quels packages ont été modifiés et d’inclure leurs dépendants. En CI, cela signifie qu’une pull request touchant un seul package ne build et ne teste que ce qu’elle peut réellement affecter.
Workspaces et structure
Turborepo ne gère pas les dépendances lui-même — c’est le rôle du gestionnaire de paquets. Vous définissez vos workspaces avec pnpm, npm, yarn ou bun, et Turborepo ajoute une couche de pipeline et de cache par-dessus.
repo/
├── apps/
│ ├── web/ # a deployable app
│ └── docs/
├── packages/
│ ├── ui/ # a shared component library
│ └── config/ # shared config
├── package.json
├── pnpm-workspace.yaml
└── turbo.json
Les applications consomment des paquets partagés via le protocole de workspace, et Turborepo s’appuie sur ce graphe de dépendances pour ordonnancer les tâches. La combinaison des workspaces pnpm pour le lien et de Turborepo pour l’exécution des tâches est la configuration de monorepo moderne la plus courante.
Bonnes pratiques
- Déclarez
outputspour chaque tâche pouvant être mise en cache. - Utilisez
dependsOnavec^pour exprimer l’ordre des dépendances. - Marquez les tâches longues, comme
dev, aveccache: false. - Activez le cache distant (remote caching) dans la CI pour obtenir les gains les plus importants.
- Filtrez par packages modifiés dans la CI pour maintenir des pipelines rapides.
- Gardez
turbo.jsonà la racine du dépôt et partagez-le entre les packages. - Ajoutez un script à la racine pour que toute l’équipe exécute les mêmes commandes.
Erreurs courantes
- Oublier
outputset perdre ainsi le bénéfice du cache. - Exécuter des tâches dans un ordre arbitraire au lieu d’utiliser
dependsOn. - Mettre en cache une tâche persistante, comme un serveur de développement.
- Inclure inutilement des variables d’environnement volatiles dans le hash.
- Exécuter l’intégralité du pipeline en CI alors qu’un filtrage permettrait d’ignorer les packages non affectés.
- Considérer Turborepo comme un remplaçant pour un gestionnaire de paquets.
Et après ?
Turborepo transforme un monorepo, d’un fardeau en un véritable avantage. Associez-le à pnpm pour la gestion des liens de workspace, maîtrisez les bases de npm et Node.js, et continuez à builder vos packages individuels avec Vite. Ensuite, ajoutez un turbo run build à la racine d’un dépôt contenant plusieurs packages et observez le second lancement se terminer presque instantanément.