ITSkillsCenter
Développement Web

Bun monorepo et publication de packages : guide complet 2026

17 min de lecture

Une équipe technique de Cotonou maintient une stack composée de quatre services Node : une API publique, une API admin, un worker de paiement, et un serveur d’envoi d’emails. Avant 2025, chaque service vivait dans son propre dépôt avec ses dépendances dupliquées et ses utilitaires recopiés. Le passage à un monorepo Bun avec workspaces a divisé par quatre le temps d’installation des dépendances en CI (de 95 à 22 secondes), unifié les conventions de code, et permis la publication d’un package interne @itskills/utils consommé par les quatre services. Ce pilier détaille pourquoi Bun est devenu en 2026 le choix le plus pragmatique pour gérer un monorepo TypeScript, comment structurer le projet, comment publier des packages internes ou publics, et comment éviter les pièges spécifiques aux projets ouest-africains. Pour les tutoriels Bun spécifiques (production, ORM, déploiement), voir les articles existants Bun en production 2026 et Déployer Bun avec systemd ou PM2.

Pourquoi Bun pour un monorepo en 2026

Bun a rejoint en 2025 la maturité que pnpm et Yarn classique offraient depuis longtemps pour la gestion de monorepos, avec trois avantages distinctifs. Premièrement, l’installation des dépendances est trois à dix fois plus rapide que pnpm sur les projets de taille moyenne, et l’écart se creuse sur les CI à connectivité limitée. Deuxièmement, le runtime Bun exécute directement le TypeScript sans passer par tsc ou tsx, ce qui simplifie les scripts de développement et réduit la dette d’outillage. Troisièmement, le bundler intégré bun build remplace une partie des configurations Vite ou esbuild pour les libs internes, avec une API minimale et des temps de build inférieurs à la seconde sur des packages typiques.

Ces gains s’accumulent au quotidien dans une équipe qui pousse plusieurs PR par jour. Sur un monorepo de cinq workspaces, le cycle « git pull → install → build → test » passe de trois minutes à moins d’une minute. Cette réduction de friction change la culture de l’équipe : on lance des tests plus souvent, on rebase plus volontiers, on extrait du code commun sans regarder à la dépense en temps d’attente.

Le coût d’adoption reste raisonnable. Pour un projet existant en pnpm ou Yarn, la migration vers Bun se fait en une journée pour un développeur expérimenté. Le format du package.json est identique, les scripts npm fonctionnent sans modification, et seuls quelques cas particuliers (postinstall scripts complexes, dépendances natives obscures) demandent un ajustement. Pour un nouveau projet, démarrer directement en Bun est le choix optimal en 2026.

Structure d’un monorepo Bun

L’arborescence canonique reprend les conventions établies par pnpm et Yarn. À la racine, un package.json qui déclare les workspaces et les scripts orchestrateurs. Dans apps, les applications déployables (services backend, frontends, workers). Dans packages, les bibliothèques internes ou publiables. Cette séparation est conceptuelle mais pratique : les apps consomment des packages, les packages ne consomment jamais d’apps. Une dépendance circulaire est ainsi techniquement impossible.

Le package.json racine déclare la liste des workspaces via la clé workspaces et active les optimisations Bun spécifiques : déduplication agressive, hoisting contrôlé, lockfile binaire ultra-compact (bun.lockb). Ce dernier point est important pour les équipes ouest-africaines : le lockfile binaire est plus petit qu’un pnpm-lock.yaml, ce qui accélère les git pull sur les connexions limitées et réduit l’empreinte du dépôt.

Pour les conventions de nommage des packages internes, on adopte un préfixe scopé propre à l’organisation : @itskills/api-types, @itskills/db-schema, @itskills/auth-core. Ce préfixe évite les collisions avec des packages npm publics, clarifie la propriété, et facilite la publication ultérieure si un package devient open-source. La règle pratique : tout package publiable a un nom scopé, tout code privé non publiable peut rester sans scope.

Configurer les workspaces Bun

La déclaration des workspaces se fait dans le package.json racine avec un tableau de glob patterns. Bun reconnaît automatiquement les sous-projets et les expose comme dépendances internes via la syntaxe "workspace:*". Cette syntaxe indique que le package consommé est résolu localement vers la version courante du workspace, sans publication intermédiaire ni lien manuel.

{
  "name": "mon-monorepo",
  "private": true,
  "workspaces": ["apps/*", "packages/*"],
  "scripts": {
    "dev": "bun run --filter '*' dev",
    "build": "bun run --filter './apps/*' build",
    "test": "bun test"
  }
}

Le filtrage --filter permet d’exécuter un script sur un sous-ensemble de workspaces. Il accepte des globs sur les noms de package ou les chemins. Pour lancer le dev de toutes les apps en parallèle, bun run --filter './apps/*' dev fait l’affaire. Pour ne tester qu’un package, bun test --filter @itskills/auth-core. Cette granularité accélère les boucles de feedback.

Pour les dépendances entre workspaces, on déclare simplement "@itskills/utils": "workspace:*" dans le package.json du consommateur. Bun crée un lien interne, et toute modification de @itskills/utils est visible immédiatement sans rebuild ni republish. Cette simplicité est l’argument principal du monorepo : on travaille comme si le code était dans le même dossier, mais avec la rigueur des frontières de package.

Partager les types et le runtime

Pour les packages partagés entre apps, deux modes coexistent. Le mode « source » expose directement les fichiers TypeScript via "main": "./src/index.ts". Bun consomme directement le source, aucune compilation préalable n’est nécessaire. Cette approche est la plus simple et fonctionne parfaitement quand toutes les apps consommatrices utilisent Bun ou un bundler compatible TypeScript (Vite, esbuild, Webpack 5+).

Le mode « compiled » produit un dossier dist/ via bun build ou tsc, avec "main": "./dist/index.js" et "types": "./dist/index.d.ts". Ce mode est obligatoire si le package est publié sur npm public, ou consommé par un environnement Node sans transpilation. Le surcoût : un step de build à chaque modification du package, géré généralement par un script watch en dev.

Pour les schémas Zod, les types métier, les helpers purs : mode source. Pour les libs publiables ou consommées par des apps Node legacy : mode compiled. Cette discipline évite l’over-engineering du build pour le code interne tout en respectant les conventions npm pour le code externe.

Publier des packages npm depuis Bun

La publication d’un package depuis un workspace Bun suit le flow npm classique avec deux subtilités. Premièrement, le champ "private": true du package racine empêche toute publication accidentelle de la racine du monorepo. Seuls les workspaces dont "private" est absent ou false sont publiables. Deuxièmement, la commande bun publish respecte les configurations .npmrc standards et fonctionne avec npm registry, GitHub Packages, ou un Verdaccio interne.

Pour la gestion des versions, deux approches coexistent. Manuelle : on incrémente les versions à la main avant chaque publication, gérable jusqu’à 5-10 packages mais source d’erreurs au-delà. Automatisée via Changesets : chaque PR ajoute un fichier markdown décrivant les changements et leur impact (patch, minor, major), un workflow GitHub Actions agrège ces changesets, génère le changelog, incrémente les versions, et publie. Cette automatisation paye dès qu’on a 5 packages ou plus à publier.

Pour les agences ouest-africaines qui livrent des projets clients, un Verdaccio auto-hébergé sur un VPS Hetzner CX22 sert de registre privé interne. Coût : 5 €/mois. Les packages sensibles (logique métier client, accès API privées) y sont publiés et consommés par tous les projets de l’agence, sans exposer le code sur npm public. C’est le pattern qu’on observe dans les studios de Dakar et Abidjan qui ont structuré leur capitalisation technique sur la durée.

CI/CD et caching dans un monorepo Bun

L’avantage du monorepo en CI tient à la possibilité d’exécuter des jobs uniquement sur les packages modifiés. Avec Bun et GitHub Actions, on combine deux mécanismes. Le filtrage par chemin via paths: dans la définition du workflow déclenche un job uniquement quand des fichiers spécifiques changent. Le cache des dépendances Bun via actions/cache sur le dossier ~/.bun/install/cache et le fichier bun.lockb évite de retélécharger les packages à chaque run, économisant 30 à 90 secondes par job.

Pour un monorepo avec quatre apps et trois packages, une CI bien configurée traite typiquement une PR en 90 à 180 secondes, contre 5 à 8 minutes sans optimisations. Ce gain se traduit directement en vélocité d’équipe : les développeurs ne passent plus par d’autres tâches en attendant la CI, le contexte mental reste sur la PR en cours, et les corrections suite à un échec CI sont immédiates.

Pour les tests, Bun expose un test runner natif compatible avec la syntaxe Vitest et Jest. bun test détecte automatiquement les fichiers *.test.ts et les exécute en parallèle. La vitesse d’exécution est trois à cinq fois supérieure à Vitest sur Node pour des suites comparables, ce qui accélère encore le cycle de feedback.

Adaptation au contexte ouest-africain

Trois bénéfices spécifiques pour les équipes ouest-africaines. Premièrement, la frugalité de Bun en bande passante : le téléchargement initial des dépendances pour un monorepo typique passe de 250 Mo (npm) à 60 Mo (Bun avec déduplication aggressive), critique pour les développeurs qui paient leur connexion au volume ou qui clonent des projets en zones à connectivité limitée comme Saint-Louis ou Bobo-Dioulasso. Deuxièmement, la rapidité de démarrage des scripts en local : bun run dev démarre en 200 ms contre 1,5 seconde pour Node + nodemon, ce qui change l’expérience de développement sur les machines moyennes que les freelances utilisent (Tecno Megabook, MSI entrée de gamme). Troisièmement, la possibilité de partager des packages entre projets clients via un Verdaccio interne capitalise le savoir-faire d’agence — un pattern de validation de numéro UEMOA développé pour un client est immédiatement disponible pour le suivant, sans copier-coller fragile.

Pour la formation des juniors locaux, Bun simplifie l’apprentissage. Là où expliquer Webpack + Babel + ts-node à un junior demande plusieurs semaines, Bun fournit un environnement où « ça marche » sans configuration. L’effort cognitif libéré peut se concentrer sur le code métier et l’architecture, ce qui accélère la montée en compétence et la prise d’autonomie.

Erreurs fréquentes à éviter

Erreur Cause Solution
Cycle de dépendances entre packages Package A importe B qui importe A Extraire le code commun dans un package C
Versions de package incohérentes Plusieurs apps consomment des versions différentes Utiliser workspace:* pour les internes
Build d’app inclut le code de tests Pattern de glob trop large Exclure *.test.ts dans la config build
Publication accidentelle de la racine Pas de "private": true Toujours déclarer dans le package.json racine
CI installe tout depuis zéro Pas de cache Bun Configurer actions/cache sur ~/.bun/install/cache
Types non résolus côté consommateur Champ "types" manquant Ajouter "types": "./src/index.ts" dans package.json

Bun vs pnpm vs Yarn pour les monorepos

Trois gestionnaires se disputent le marché des monorepos en 2026. Bun gagne sur la performance brute et l’intégration runtime + bundler + test runner. pnpm reste la référence stable, avec un écosystème éprouvé et une compatibilité maximale. Yarn 4 (Berry) propose des fonctionnalités avancées (Plug’n’Play, zero-installs) qui séduisent certaines grosses entreprises mais ajoutent de la complexité.

Pour un nouveau projet en 2026, Bun est notre recommandation par défaut sauf besoin spécifique. Pour une migration depuis pnpm, l’opération prend une journée et apporte un gain de vitesse mesurable. Pour les projets qui doivent rester sur Node legacy avec dépendances natives obscures, pnpm reste le choix sûr. Yarn 4 s’envisage pour les très grandes équipes habituées à son écosystème.

Pour aller plus loin

Tutoriels du cluster Bun monorepo :

Articles connexes : Bun en production 2026 · Bun avec systemd ou PM2 · Hono RPC + SvelteKit monorepo.

Doc officielle : Bun install · Bun workspaces.

FAQ

Bun est-il stable pour la production en 2026 ?
Oui pour la grande majorité des cas. Plusieurs SaaS B2B en Afrique de l’Ouest le déploient avec succès depuis 2024-2025. Quelques edge cases (drivers natifs très spécifiques, modules Node profondément couplés à libuv) restent imparfaits — vérifier la compatibilité avant de s’engager.

Peut-on mélanger Bun et Node dans un même monorepo ?
Oui. Bun gère l’install même pour des packages destinés à tourner sous Node en production. Le runtime peut être différent par app : une app peut être démarrée par Node, une autre par Bun, dans le même monorepo.

Comment migrer un monorepo pnpm vers Bun ?
Trois étapes : supprimer pnpm-lock.yaml et node_modules, ajouter workspaces au package.json racine, lancer bun install. Vérifier que les scripts postinstall et les dépendances natives fonctionnent.

Faut-il TurboRepo en plus de Bun ?
Pas pour les monorepos jusqu’à 10 packages. Au-delà, ou si on a besoin d’un cache distant performant pour la CI, TurboRepo apporte de la valeur, et il s’intègre proprement avec Bun.

Comment gérer les versions Node compatibles ?
Déclarer "engines": { "node": ">=22" } dans chaque app et utiliser volta ou fnm pour pinner la version Node localement. Bun lit ces metadata sans interférer.

Cas d’étude : monorepo de plateforme logistique à Cotonou

Une plateforme logistique béninoise gère le transport entre Cotonou, Porto-Novo et Lomé pour 80 commerçants quotidiens. Leur stack repose sur un monorepo Bun avec sept workspaces : trois apps (back-office admin, app coursier mobile, API partenaires) et quatre packages partagés (types métier, schémas de validation, helpers de calcul tarifaire, client SMS unifié). Le passage à cette structure en mars 2025 a transformé leur productivité technique. Avant : trois jours pour ajouter un nouveau pays de livraison (Togo) parce qu’il fallait modifier sept dépôts en gardant la cohérence des types tarifaires. Après : une demi-journée, une seule PR, types automatiquement propagés.

L’équipe technique de cinq développeurs (deux à Cotonou, deux à Lomé, un à Porto-Novo) collabore en remote sur ce monorepo. La synchronisation passe par GitHub avec des règles de protection de branche standard. Les revues de code croisées entre dévs des trois pays maintiennent la cohérence du codebase. Le CI tourne sur un runner GitHub gratuit et boucle en moins de deux minutes pour la plupart des PR. Les coûts d’infrastructure complète — hébergement Hetzner, registre privé Verdaccio, CI/CD, monitoring — restent sous 25 €/mois pour servir 5 000 utilisateurs actifs.

Trois leçons retenues par cette équipe. D’abord, investir dès le départ dans la qualité des packages partagés paye sur la durée — un schéma Zod de pays UEMOA réutilisé dans sept endroits évite sept divergences potentielles. Ensuite, la documentation interne des packages dans des fichiers README.md par workspace facilite l’arrivée de nouveaux développeurs (l’équipe est passée de 2 à 5 sur l’année). Enfin, le caching CI bien configuré rend les boucles de feedback indolores, ce qui change la culture du déploiement : on déploie maintenant cinq à dix fois par semaine au lieu de une fois par sprint.

Sécurité et gestion des secrets

Un monorepo concentre du code de plusieurs apps, augmentant la surface d’attaque potentielle. Trois mesures essentielles. Premièrement, isoler les secrets par app : chaque app a son propre .env (jamais commité), chargé par son propre processus, jamais partagé dans des packages communs. Un package partagé qui aurait besoin d’un secret le reçoit en argument de fonction, pas via une variable d’environnement globale. Deuxièmement, scanner les dépendances avec un outil comme bun audit ou Snyk Open Source pour détecter les vulnérabilités connues — particulièrement utile pour un monorepo qui peut avoir 500 à 2 000 dépendances transitives. Troisièmement, signer les commits Git avec GPG pour garantir l’authenticité des contributions, surtout dans les équipes distribuées.

Pour les agences qui livrent des projets clients, séparer les bases de code clients dans des dépôts distincts reste la règle. Un monorepo n’est pas la bonne réponse pour fusionner du code de plusieurs clients : les frontières juridiques (NDA, propriété intellectuelle), les exigences de conformité (RGPD, lois locales), et le risque de fuite croisée pèsent plus lourd que le gain de capitalisation. Le monorepo est interne à un projet ou à un produit, pas inter-clients.

Patterns avancés et best practices

Trois patterns avancés émergent dans les monorepos matures. Le premier est l’extraction d’un package config qui centralise toutes les configurations partagées (ESLint, Prettier, TypeScript base, Vitest defaults). Chaque app importe la config commune et la spécialise si besoin. Cette approche évite la dérive des conventions entre apps et facilite les évolutions de configuration globales. Le second est l’utilisation de « boundary tests » qui vérifient que les packages partagés n’importent jamais de code spécifique à une app. Un script de validation lance un grep récursif sur les imports et bloque la PR si une violation est détectée. Cette discipline architecturale évite la régression silencieuse vers le couplage. Le troisième est la documentation des décisions architecturales via un dossier docs/adr/ contenant des Architecture Decision Records — une page markdown par décision majeure, expliquant le contexte, les options considérées, et le choix final. Ces ADR servent de mémoire collective et évitent les débats récurrents sur des décisions déjà prises.

Évolutivité et anti-patterns

Un monorepo bien structuré supporte la croissance d’une équipe de 1 à 50 développeurs sans réorganisation majeure. Au-delà, la latence Git, les conflits de merge, et la complexité des CI commencent à peser. Quelques signaux indiquent qu’un monorepo a atteint ses limites : le temps de git status dépasse plusieurs secondes, les PR ouvertes simultanément se collisionnent fréquemment sur les mêmes fichiers, ou le temps de CI total dépasse 15 minutes même avec caching. Dans ces cas, on évalue la séparation par domaine fonctionnel ou par équipe.

Côté anti-patterns à éviter, le plus fréquent est la création prématurée de packages « shared » qui ne sont en réalité utilisés que par une seule app. Cette factorisation anticipée ajoute de la complexité de gestion (versions, builds, dépendances) sans bénéfice. La règle pratique : créer un package partagé seulement quand un code est utilisé par au moins deux consommateurs avec des évolutions clairement indépendantes. Tant qu’un code est mono-consommateur, il reste dans l’app qui l’utilise, quitte à le déplacer plus tard si nécessaire.

Synthèse et recommandation finale

Pour 2026, Bun est notre recommandation par défaut pour les nouveaux monorepos TypeScript. La combinaison performance brute, simplicité de configuration, et écosystème mature en fait un choix pragmatique pour la grande majorité des cas. Les freelances et agences ouest-africaines qui veulent capitaliser leur savoir-faire technique sur la durée gagnent à structurer leurs projets en monorepo dès le début, même quand le projet ne contient qu’une seule app — la structure prête pour la croissance évite la coûteuse réorganisation ultérieure. Pour les projets existants en pnpm ou Yarn qui fonctionnent bien, la migration n’est pas urgente, mais elle apportera un gain mesurable au prochain rafraîchissement majeur de la stack.

L’investissement initial — apprendre les conventions de workspaces, structurer les packages partagés, configurer la CI — se rentabilise typiquement en deux à trois mois sur une équipe active. Le retour sur investissement est ensuite continu : chaque nouvelle feature, chaque nouveau développeur, chaque nouveau projet bénéficie de la structure en place. Pour les équipes qui hésitent par crainte de la complexité, le conseil pratique est de démarrer simple : deux apps, un package partagé, un CI minimal. La croissance se fera ensuite naturellement, guidée par les besoins réels et non par l’anticipation de scenarii hypothétiques.

Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité