Monorepo vs Polyrepo : le choix de stack qui s'impose

Résumé

Pour la plupart des devs solo qui construisent un produit avec des packages partagés, monorepo est le bon défaut en 2026. Ce guide explique ce que tu gagnes vraiment au-delà du pitch théorique, quand polyrepo gagne vraiment, quels coûts CI attendre, et comment les outils de coding IA comme Cursor et Claude Code ont modifié les équilibres classiques. Plus trois signaux concrets qui te disent qu'il est temps de splitter en repos séparés.

Poste de travail de dev avec deux moniteurs affichant la structure de repository git dans un IDE sombre, vue nocturne de Taipei par la fenêtre

La question monorepo vs polyrepo remonte avant chaque nouveau projet, et la réponse façonne des mois de setup CI/CD, de refactoring, et de contrôle d'accès. Pour la plupart des devs solo qui construisent un produit avec du code partagé, le bon défaut en 2026 est monorepo. Pas parce que c'est le choix trendy, mais parce qu'il élimine la cérémonie de publication que les polyrepos imposent au moment où deux packages ont besoin de se parler. Si tes services sont vraiment indépendants et ne partageront jamais de code, polyrepo est plus simple. Dans tous les autres cas, c'est du contexte.

Il est 22h. T'as un nouveau projet qui prend forme : une API backend, un package de types TypeScript partagés, et un dashboard frontend qui consommera forcément les deux. Deux tabs ouvertes. Le curseur clignote.

La plupart des posts sur le sujet sont écrits pour des équipes de vingt devs avec un DevOps dédié qui aime configurer Bazel. Celui-ci est pour ceux qui doivent trancher avant le premier commit, parce que restructurer six mois après, quand tu as des vrais users et un pipeline CI que tu maîtrises d'instinct, c'est le genre de truc qui tue un side project sans retour.

Ce qu'un monorepo te donne vraiment (pas la version livre)

Le pitch standard c'est « un repo, dépendances partagées, atomic changes ». C'est tout réel. Mais ce qui compte vraiment jour après jour pour un builder solo, c'est plus concret : tu n'as pas à publier des packages pour les utiliser localement.

Dans une setup polyrepo, si shared-utils a besoin d'un fix qui touche aussi api-service, soit tu publies une nouvelle version de shared-utils, tu bumps la dépendance dans api-service, tu attends le CI, puis tu déploies. Soit tu fais des hacks npm link qui marchent jusqu'à ce qu'ils ne marchent plus au milieu d'un sprint. Dans un monorepo avec des workspaces, tu changes le code, et chaque package qui l'importe voit le changement tout de suite. Pas de cérémonie de publication.

Voilà ce que ça donne avec pnpm workspaces, qui ajoute un minimum de config :

/packages
  /shared-types      ← importé directement par api et web
  /api
  /web
package.json         ← workspace root avec champ "workspaces"
// api/package.json
{
  "dependencies": {
    "@myapp/shared-types": "workspace:*"
  }
}

Pas de publication. Pas de version bump en dev. workspace:* résout le package local, et les project references TypeScript te donnent une compilation incrémentale sur tout le graphe.

Le deuxième vrai bénéfice : le refactoring cross-package qui atterrit en une PR. Tu renommes une interface dans shared-types ? TypeScript te dit chaque consumer qui a cassé, dans le même codebase, dans la même session d'éditeur. En polyrepo, tu la renommes dans repo A, tu publies une nouvelle version, et tu découvres le bris dans repo B trois jours après quand un collègue run npm install et que les types ne matchent pas le runtime.

Le troisième bénéfice, que les devs solo sous-estiment : une place pour la tooling config. Un .eslintrc, un prettier.config.js, un seul fichier CI workflow. Petits gains par changement, mais ça s'accumule sur des mois d'itération.

Il est utile de dire ce qu'un monorepo ne te donne pas : il n'élimine pas le couplage entre services. Si tes services sont vraiment indépendants et que tu les mets quand même dans un monorepo, t'as ajouté de la coordination sans retour. Les bénéfices du monorepo se matérialisent seulement quand les services partagent vraiment du code ou ont besoin de changer ensemble. La structure du repo doit refléter la structure des dépendances, pas l'imposer.

Visualisation abstraite comparant un arbre monorepo unique versus plusieurs boîtes polyrepo

Quand polyrepo se justifie vraiment

Polyrepo n'est pas une erreur. C'est le bon choix pour des situations précises, et prétendre le contraire, c'est comment tu finiras avec un monorepo de 40 services qui prend 25 minutes à cloner.

Le cas le plus clair : services avec vraiment un ownership différent, des cycles de release différents, ou des exigences de compliance différentes. Si ton service de billing est PCI-scoped et ton site marketing ne l'est pas, garder chacun dans son repo, c'est garder le contrôle d'accès, les audit logs, et le blast radius clean et séparé. C'est pas de la friction opérationnelle. C'est la feature.

Polyrepo gagne aussi quand tu open-sources une partie du codebase. Un repo public dédié te laisse les contributeurs externes fork et PR sans pull ton infra privée en scope. Le modèle de permissions par repository de GitHub ne te donne pas une isolation d'accès par paths à l'échelle. Un repo séparé gère ça correctement.

Et pour du pure microservices avec des tech stacks carrément différents : un service Go et une app React Native qui ne partagent littéralement rien au niveau code, monorepo ajoute du coût de coordination sans livrer le bénéfice. S'il n'y a pas de packages partagés, il n'y a rien à partager.

La version honnête de ça : la plupart des indie projects qui commencent en polyrepo finissent par le regretter, pas parce que polyrepo est une mauvaise architecture, mais parce qu'ils ont surestimé l'indépendance des parties. Le frontend finit toujours par avoir besoin d'un type du backend. Le worker finit toujours par avoir besoin d'une utility de l'API. Deux repos deviennent quatre PRs par feature.

Le coût CI/CD que personne ne mentionne jusqu'à ce qu'il frappe ta facture

Les monorepos ont un vrai coût opérationnel : si ton CI run naïvement tout sur chaque commit, tu pales en temps et en money pour des builds et des tests qui n'ont rien à voir avec ce que t'as changé.

T'as pushé un tweak CSS au package web. CI run la full test suite pour api, worker, et shared-types. C'est six minutes de GitHub Actions compute pour une couleur. À l'échelle, ça crée des queues CI qui bloquent toute l'équipe.

La solution existe, mais elle demande du setup intentionnel : des outils d'orchestration de build qui comprennent ton graphe de dépendances. Turborepo et Nx résolvent ça tous les deux. Le turbo.json de Turborepo définit un pipeline où chaque tâche run seulement pour les packages avec des inputs changés :

{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "cache": true
    }
  }
}

Avec le remote caching activé (gratuit sur Turborepo Cloud tier Vercel pour les petites équipes), un cache hit sur un package inchangé est instantané, pas de rebuild, pas de retest. Pour un dev solo sur un side project, ça tient le CI sous deux minutes sur la plupart des pushes une fois que les build artifacts sont warm.

Le coût : faut que tu apprennes Turborepo ou Nx avant d'en avoir besoin, pas après. C'est à peu près une demi-journée de setup. Si tu skip ça et laisse le CI grossir, le monorepo CI va ralentir au point où tu vas commencer à remettre en question tout le choix architectural, et c'est typiquement quand les devs décident que polyrepo avait raison, alors que le vrai problème était juste un fichier config manquant.

Dashboard de pipeline CI/CD montrant les jobs de build parallèles et le statut de déploiement pour un monorepo

Comment les outils IA ont changé l'équilibre du débat

Jusqu'à récemment, un argument vrai pour polyrepo était la charge cognitive : les petits repos sont plus faciles à raisonner parce qu'ils sont isolés. Tu context-switch sur un service nouveau, tu vois juste ce qui est pertinent pour ce service. L'argument était légitime.

Les outils de coding IA changent le calcul. Quand tu travailles avec Cursor, Claude Code, ou GitHub Copilot, l'outil travaille avec ton codebase complet en contexte. Il voit les dépendances cross-service, comprend quelle interface est consommée par quel service, et peut tracker un champ renommé à travers chaque consumer sans que tu tiennes le mental model toi-même. L'argument « le petit repo isolé est plus facile à comprendre » s'affaiblit beaucoup quand ton assistant IA tient tout le graphe de dépendances en contexte de toute façon.

Un exemple concret : en setup polyrepo, si tu demandes à un assistant IA de refactorer un endpoint API qui affecte aussi un type partagé, typiquement il ne peut pas voir les deux repos en une session. T'es en train de faire la coordination manuellement, c'est exactement la friction qu'un monorepo était supposé éliminer. En monorepo, le même refactor c'est une conversation.

Ca ne flip pas la décision complètement. Mais ça retire une des justifications historiques pour polyrepo pour les petites équipes et les devs solo, et ça penche le défaut un peu plus vers monorepo quand le code est vraiment couplé.

Trois signaux que tu dois splitter le repo maintenant

T'as commencé avec un monorepo. Bien. Mais voici les signaux concrets que le split est devenu le bon appel :

Le contrôle d'accès devient critical. Un contractor a besoin d'accès frontend, pas backend. Une équipe d'intégration partner a besoin de lire ton API schema mais rien de propriétaire. Le Codeowners de GitHub peut limiter qui peut review quels paths, mais ça ne limite pas l'accès en lecture. Si l'isolation de lecture compte pour compliance ou security, les repos séparés sont la réponse clean. Les gymnastics Codeowners ne remplacent jamais complètement les permissions au niveau repository.

Les fails CI dans un service bloquent le déploiement dans un autre. Si un broken test dans payment-service gate un hotfix que tu dois ship dans marketing-site, ton monorepo crée un couplage que ton codebase n'a pas. Soit la config de build a besoin de fix (task scoping avec Turborepo va résoudre ça), soit les deux services n'appartiennent vraiment pas au même repo.

Une partie va open-source et une non. C'est le cas de split le plus clean. Extract la pièce open-source dans son propre repo public. Du code mixed public/private dans un monorepo GitHub est vraiment douloureux : tu aurais besoin d'une organization séparée ou d'un process de pruning manuel qui crée une maintenance overhead permanente.

La setup pratique où la plupart des builders se retrouvent

La réponse où la plupart des devs expérimentés se stabilisent : un monorepo par product domain, pas « un monorepo pour tout ce que t'as jamais construit » et pas « un repo par package ».

Si tu construis une SaaS avec un frontend web, une API, et une shared type library, c'est un produit. Garde ça dans un monorepo. Si tu maintiens aussi une CLI utility open-source que d'autres projets utilisent, c'est un repo différent avec une audience et un cycle de release différents.

L'erreur c'est de traiter le choix monorepo/polyrepo comme idéologique. C'est pas « les équipes monorepo » versus « les équipes polyrepo ». C'est une décision structurelle basée sur trois questions : quel est le graphe de dépendances entre tes services ? Qui a besoin d'accès à quoi, et est-ce que l'isolation compte ? Quelle est ta tolérance pour la complexité du setup CI/CD ?

Dev solo travaillant sur un laptop considérant les décisions d'architecture d'un projet

Pour les side projects spécifiquement : commence avec un monorepo utilisant pnpm workspaces (npm workspaces marche aussi, juste moins ergonomic). Ajoute Turborepo seulement quand ton CI commence régulièrement à frapper 4+ minutes. Splitte en un repo séparé seulement quand t'as une raison concrète : open-source, contrôle d'accès, compliance, ou une équipe partner avec un cycle de release différent. Pas parce que ça semble plus architecturalement clean.

Le débat monorepo vs polyrepo est un de ces choix où la bonne réponse pour la plupart des devs solo est pareille : commence simple, optimise quand la friction spécifique apparaît. Le curseur clignote toujours. Ship le premier commit.

Questions fréquentes

Un monorepo est-il mieux pour les outils IA comme Cursor ou GitHub Copilot ?
Oui, généralement. Les assistants IA codent au mieux quand ils peuvent voir le graphe de dépendances complet en une fenêtre de contexte. En monorepo, un outil comme Cursor peut tracer un changement depuis un type partagé à travers chaque consumer en une session. En polyrepo, ce contexte cross-repo manque ou demande du setup manuel, ça remet la coordination sur toi.
Quelle est la vraie différence entre Turborepo et Nx ?
Les deux sont des outils d'orchestration de build pour monorepo qui skippent les builds des packages inchangés en utilisant l'analyse du graphe de dépendances. Turborepo est plus simple à configurer et marche bien pour les projets JavaScript/TypeScript. Nx est plus riche avec des generators intégrés, une UI de project graph, et du support multi-langage. Pour un side project, Turborepo est typiquement le bon point de départ.
Je peux migrer de polyrepo à monorepo plus tard ?
Oui, mais c'est assez disruptif pour que tu le fasses intentionnellement. Le process implique de déplacer chaque package dans une structure workspace, updater les imports, ajuster les pipelines CI, et optionnellement réécrire l'historique git avec git subtree ou git-filter-repo. La plupart des équipes qui l'ont fait disent que ça valait le coup, mais budget deux à trois jours minimum pour un projet de taille pertinente.
Est-ce que les grandes boîtes utilisent des monorepos ?
Google, Meta, Microsoft, et Twitter ont tous historiquement utilisé des monorepos pour leurs codebases principales. Les équipes iOS et Android d'Uber ont toutes les deux switchées à monorepo spécifiquement pour réduire la friction de coordination cross-service. Cela dit, les outils que ces boîtes utilisent (Bazel, Buck, Pants) sont beaucoup plus complexes que ce qu'un dev solo a besoin. Turborepo et pnpm workspaces couvrent 95% des bénéfices sans l'overhead infra.
Est-ce qu'un monorepo affecte comment je déploie sur Vercel ou autre ?
La plupart des platforms modernes gèrent les monorepos nativement. Vercel te laisse spécifier une root directory par projet, donc tu peux déployer packages/web tout en pointant la commande build vers la root du monorepo. Netlify et Railway ont du support similaire. La config prend environ dix minutes et ne demande pas d'infra spéciale au-delà de ce que tu as déjà.
Est-ce qu'un dev solo doit setup Turborepo dès le premier jour ?
Pas nécessairement. Commence avec pnpm workspaces pour les bénéfices de shared packages. Ajoute Turborepo quand ton CI commence régulièrement à prendre plus de trois à quatre minutes, ou quand tu veux du remote caching pour accélérer les builds locaux. Ajouter Turborepo à une setup workspace existante prend à peu près trente minutes, donc tu ne te locks pas en attendant.