Nehos Groupe

Ce qu'il faut retenir

Les micro-frontends répondent à un problème réel — mais uniquement au-delà d'un certain seuil de complexité organisationnelle et technique. Avant trois équipes frontend indépendantes et un découpage domaine métier clair, un monorepo bien structuré suffit et évite la surcharge architecturale.

Webpack Module Federation 5 reste le pattern de référence pour les projets Next.js B2B en 2026 : exposition de modules distants à la demande, partage de dépendances pour éviter la duplication de bundle, déploiement totalement indépendant par micro-app. L'intégration native avec Next.js 15 via le plugin @module-federation/nextjs-mf s'est considérablement simplifiée.

Les trois pièges les plus courants en production : la duplication de bundle React/ReactDOM quand le partage de dépendances est mal configuré, la régression des Core Web Vitals (LCP et CLS) due à l'hydration asynchrone des remotes, et l'absence de stratégie de design system partagé qui génère une incohérence visuelle progressive entre les micro-apps.

Le déploiement indépendant — le bénéfice central des micro-frontends — exige une infrastructure adaptée : CDN avec invalidation de cache granulaire par micro-app, versioning des remotes exposés, et un shell applicatif qui gère les fallbacks quand un remote est indisponible.

Micro-frontend 2026 : architecture et implémentation pour projets B2B

Le découpage d'une interface en micro-apps indépendantes n'est pas une tendance — c'est une réponse architecturale concrète aux contraintes des grandes applications B2B : équipes multiples, déploiements découplés, domaines métier distincts. Voici ce que j'ai appris en production.

Adapté à toute taille de structure

Artisan
Startup
PME / TPE
ETI
Grand Groupe
C
Chokri Siala
··next-headless

#Pourquoi les micro-frontends deviennent incontournables pour les grandes apps B2B

La question n'est pas «est-ce que les micro-frontends sont une bonne idée» — c'est «est-ce que votre situation spécifique justifie la complexité qu'ils introduisent». Cette nuance est essentielle, et j'y reviendrai en dernière section.

Pour les organisations qui réunissent les conditions d'application — et elles sont nombreuses parmi les ETI et grands comptes B2B — les micro-frontends répondent à des problèmes concrets qui ne peuvent pas être résolus autrement.

#Le problème du couplage au sein d'un frontend monolithique

Un frontend monolithique de grande taille développé sur 3 à 5 ans présente des caractéristiques prévisibles : des centaines de composants dans un même dépôt, des dizaines de développeurs qui se marchent dessus sur les mêmes fichiers, des builds de 20 minutes, des tests d'intégration qui durent une heure, et une mise en production unique qui bloque toutes les équipes si un seul module régresse.

Quand l'équipe Catalogue produits ne peut pas déployer sa nouvelle feature parce que l'équipe Checkout a cassé un test, ce n'est pas un problème de discipline — c'est un problème d'architecture. Le couplage technique entre des domaines métier distincts génère une friction opérationnelle qui croît exponentiellement avec la taille de l'équipe.

#Ce que les micro-frontends permettent réellement

La promesse centrale des micro-frontends tient en trois points :

Autonomie d'équipe : chaque équipe possède son micro-frontend de bout en bout (design, développement, CI/CD, monitoring). Elle peut déployer en production à tout moment sans coordination avec les autres équipes. Cette autonomie réduit la charge cognitive collective et accélère la vélocité de chaque stream.

Découpage domaine métier : chaque micro-frontend correspond à un bounded context du domaine métier — Catalogue, Checkout, Espace client, Dashboard analytics, Administration. Ce découpage aligne l'architecture frontend sur l'architecture microservices du backend, créant une cohérence systémique.

Déploiements indépendants : une micro-app peut être redeployée sans toucher au shell ni aux autres remotes. Un bug en production sur le module Facturation n'impacte pas le module Commandes. Le blast radius d'une mauvaise mise en production est strictement limité à son scope.

Ces bénéfices sont réels — mais ils ont un coût d'entrée significatif que les équipes sous-estiment systématiquement. Ce coût, c'est la complexité infrastructurale, la cohérence transversale (design system, authentification, state partagé) et le surcoût de debugging sur des systèmes distribués.

Pour les équipes qui arrivent d'un monolithe et envisagent une migration, le passage aux micro-frontends s'inscrit souvent dans une stratégie plus large de refonte technique dont il faut évaluer le ROI global.


#Patterns d'implémentation : Module Federation, iframes, Web Components, monorepo splits

Quatre grandes approches coexistent en 2026, avec des profils de complexité et de cas d'usage très différents.

#Module Federation (Webpack 5 / Rspack)

Module Federation est le pattern dominant pour les projets Next.js et React en production. Il permet à une application (le host ou shell) de charger dynamiquement des modules exposés par d'autres applications (remotes), avec partage optionnel de dépendances communes (React, ReactDOM, design tokens).

L'avantage clé : les remotes sont des bundles JavaScript autonomes déployés indépendamment sur un CDN. Le shell charge le manifest de chaque remote au runtime, pas au build time — ce qui rend possible le déploiement indépendant sans rebuild du shell.

#iframes

L'approche la plus simple et la plus isolée : chaque micro-app tourne dans son propre iframe. L'isolation est totale (CSS, JavaScript, DOM). La communication inter-apps passe par postMessage.

Cette approche est sous-estimée pour des cas d'usage spécifiques : intégration de modules tiers dont on ne maîtrise pas le code, migration progressive d'applications legacy, outils d'administration internes où la performance n'est pas critique. SAP l'utilise massivement dans ses produits enterprise. L'inconvénient principal est l'impact sur les Core Web Vitals (chaque iframe génère un sous-contexte de rendu séparé) et la complexité de l'accessibilité.

#Web Components

Les Web Components (Custom Elements + Shadow DOM + HTML Templates) permettent d'encapsuler une micro-app dans un élément HTML custom (<product-catalog />) framework-agnostique. Un Web Component peut être développé en React, Vue ou Svelte et consommé par n'importe quel autre framework.

En B2B 2026, les Web Components sont pertinents pour exposer des modules à des équipes utilisant des stacks différentes (équipe React qui consomme un module Angular legacy, par exemple). La limitation reste l'intégration avec le SSR Next.js — les Web Components sont fondamentalement client-side, ce qui complique le rendu serveur et impacte le LCP.

#Monorepo splits (Turborepo / Nx)

Avant de passer aux micro-frontends à déploiement indépendant, une étape intermédiaire est souvent suffisante : découper le code en packages indépendants au sein d'un monorepo. Avec Turborepo ou Nx, chaque domaine métier vit dans son propre package avec ses propres tests, sa propre pipeline CI, tout en restant dans un déploiement coordonné.

Cette approche donne 80 % des bénéfices de l'isolation de code (autonomie d'équipe, tests indépendants, clear ownership) sans la complexité du chargement de remotes à runtime. Elle convient aux équipes de 2 à 8 développeurs frontend.


#Webpack Module Federation 5 avec Next.js : setup technique détaillé

Voici le setup concret que Nehos utilise en production sur les projets B2B de grande taille en 2026, avec Next.js 15 et le plugin officiel @module-federation/nextjs-mf.

#Architecture cible

shell-app/          # Next.js — host, routing principal, auth
catalogue-mfe/      # Next.js — remote, domaine Catalogue produits
checkout-mfe/       # Next.js — remote, domaine Checkout/Panier
dashboard-mfe/      # Next.js — remote, domaine Analytics/Reporting
shared-ui/          # Package — design system partagé (tokens, composants)

#Configuration du shell (host)

// shell-app/next.config.mjs
import { NextFederationPlugin } from '@module-federation/nextjs-mf';

const remotes = (isServer) => {
  const location = isServer ? 'ssr' : 'chunks';
  return {
    catalogue: `catalogue@${process.env.CATALOGUE_MFE_URL}/_next/static/${location}/remoteEntry.js`,
    checkout: `checkout@${process.env.CHECKOUT_MFE_URL}/_next/static/${location}/remoteEntry.js`,
    dashboard: `dashboard@${process.env.DASHBOARD_MFE_URL}/_next/static/${location}/remoteEntry.js`,
  };
};

export default {
  webpack(config, options) {
    config.plugins.push(
      new NextFederationPlugin({
        name: 'shell',
        remotes: remotes(options.isServer),
        shared: {
          react: { singleton: true, requiredVersion: '^18.3.0' },
          'react-dom': { singleton: true, requiredVersion: '^18.3.0' },
          '@shared-ui/tokens': { singleton: true },
        },
        extraOptions: { skipSharingNextInternals: false },
      })
    );
    return config;
  },
};

#Configuration d'un remote (catalogue-mfe)

// catalogue-mfe/next.config.mjs
import { NextFederationPlugin } from '@module-federation/nextjs-mf';

export default {
  webpack(config, options) {
    config.plugins.push(
      new NextFederationPlugin({
        name: 'catalogue',
        filename: 'static/chunks/remoteEntry.js',
        exposes: {
          './ProductGrid': './src/components/ProductGrid',
          './ProductDetail': './src/components/ProductDetail',
          './CategoryNav': './src/components/CategoryNav',
        },
        shared: {
          react: { singleton: true, requiredVersion: '^18.3.0' },
          'react-dom': { singleton: true, requiredVersion: '^18.3.0' },
        },
      })
    );
    return config;
  },
};

#Consommation dans le shell

// shell-app/src/app/catalogue/page.tsx
import dynamic from 'next/dynamic';

const ProductGrid = dynamic(
  () => import('catalogue/ProductGrid').catch(() => import('./fallbacks/ProductGridFallback')),
  {
    loading: () => <ProductGridSkeleton />,
    ssr: false, // ou true si le remote supporte le SSR
  }
);

export default function CataloguePage() {
  return (
    <main>
      <ProductGrid />
    </main>
  );
}

Le .catch() dans le dynamic import est critique : si le remote CDN est indisponible, le shell affiche un fallback plutôt que de crasher. Ce fallback peut être un squelette statique ou un composant minimal servi depuis le shell lui-même.

#Rspack comme alternative

Rspack (le bundler Rust-based compatible Webpack) supporte Module Federation depuis la version 0.6. Sur les projets avec des builds dépassant 5 minutes, la migration vers Rspack réduit le build time de 60 à 80 % — tout en gardant la même configuration Module Federation. Cette migration sera abordée dans un article dédié.


#Routing et navigation : gérer la cohérence entre micro-apps

Le routing est l'un des défis techniques les plus complexes en architecture micro-frontend. Chaque micro-app a son propre routeur interne, mais l'utilisateur doit percevoir une expérience de navigation unifiée.

#Approche 1 : routing centralisé dans le shell

Le shell Next.js possède l'intégralité des routes de l'application. Chaque route charge le composant correspondant depuis le bon remote. C'est l'approche la plus simple et la plus cohérente du point de vue utilisateur.

/catalogue/*         → catalogue-mfe/ProductGrid, ProductDetail
/checkout/*          → checkout-mfe/CartPage, PaymentPage
/dashboard/*         → dashboard-mfe/AnalyticsPage

Le shell gère les transitions de route, le prefetching et le back/forward. Les remotes exposent des composants de page, pas des applications avec leur propre routeur.

#Approche 2 : routing délégué aux remotes

Chaque remote gère ses propres sous-routes. Le shell délègue tout ce qui commence par /catalogue/ au remote Catalogue, qui utilise son propre Next.js App Router. Cette approche offre plus d'autonomie aux équipes remote mais génère une complexité de synchronisation d'état de navigation entre le shell et le remote.

En pratique, l'approche 1 (routing centralisé) est préférable pour les projets où l'expérience utilisateur est critique. L'approche 2 convient mieux aux outils internes où chaque domain fonctionne de façon quasi-autonome (ex : backoffice multi-modules).

Quand un remote doit déclencher une navigation vers une route appartenant à un autre remote (ex : le Catalogue redirige vers le Checkout après un ajout au panier), deux patterns sont possibles :

Event Bus : le remote émet un événement custom (CustomEvent('navigate', { detail: { to: '/checkout/cart' } })) que le shell écoute et traduit en navigation Next.js.

Callback props : le shell injecte une prop onNavigate dans chaque composant remote. Le remote l'appelle quand une navigation cross-app est nécessaire. Plus explicite, mais couplage légèrement plus fort.

Le pattern Event Bus est préférable dans les architectures où les remotes ne doivent pas connaître l'API du shell. Pour aller plus loin sur les stratégies de routing dans les projets Next.js App Router, l'article dédié détaille les options disponibles.


#Design system partagé : tokens, composants, versioning

Sans stratégie explicite de design system partagé, les micro-frontends dérivent inévitablement : chaque équipe prend des raccourcis visuels, les espacements divergent, les couleurs mutent légèrement d'un module à l'autre. Ce drift visuel est perceptible par les utilisateurs et coûteux à corriger rétrospectivement.

#Architecture recommandée

packages/
  shared-ui/
    tokens/         # Design tokens (couleurs, typo, spacing) — source de vérité
    components/     # Composants React partagés (Button, Input, Modal, Table)
    hooks/          # Hooks utilitaires partagés
    styles/         # CSS global, reset, animations

Le package shared-ui est publié dans le registre npm interne (Verdaccio, GitHub Packages ou npm private) et consommé par tous les remotes comme dépendance classique. Il est configuré comme singleton dans la config Module Federation — une seule instance partagée à runtime, sans duplication.

#Design tokens comme source de vérité

Les design tokens (définissant les couleurs, typographies, spacings, breakpoints, ombres) doivent vivre dans un fichier source unique, idéalement synchronisé avec Figma via un plugin d'export (Style Dictionary, Token Pipeline).

// packages/shared-ui/tokens/index.ts
export const tokens = {
  color: {
    brand: { primary: '#1A56DB', secondary: '#0E9F6E' },
    neutral: { 50: '#F9FAFB', 900: '#111928' },
    semantic: { error: '#E02424', warning: '#C27803', success: '#057A55' },
  },
  spacing: { xs: '4px', sm: '8px', md: '16px', lg: '24px', xl: '40px' },
  radius: { sm: '4px', md: '8px', lg: '16px', full: '9999px' },
  shadow: { card: '0 1px 3px rgba(0,0,0,0.1)', modal: '0 20px 60px rgba(0,0,0,0.15)' },
} as const;

#Stratégie de versioning du design system

Le versioning sémantique (SemVer) est obligatoire pour le design system partagé. Les règles :

  • Patch (1.0.x) : corrections de bugs, ajustements mineurs sans impact visuel
  • Minor (1.x.0) : nouveaux composants ou nouvelles props rétrocompatibles
  • Major (x.0.0) : changements breaking (renommage de composants, changement de tokens existants)

Les remotes épinglent une version majeure ("@shared-ui/tokens": "^1.0.0") et migrent vers la version majeure suivante lors d'un sprint dédié. Cette discipline évite les incompatibilités visuelles inattendues entre les équipes.

Cette approche s'intègre naturellement dans une stratégie monorepo avec Turborepo où le design system est un package workspace interne.


→ Vous évaluez vos options ? Utilisez notre estimateur de budget en ligne pour obtenir une fourchette en 2 minutes, ou consultez nos tarifs détaillés.

#State management cross-app : quelles solutions en 2026

Le state management dans une architecture micro-frontend est fondamentalement différent d'une application monolithique : il n'existe pas de store global unique accessible à toutes les micro-apps. Chaque remote a son propre contexte React, ses propres hooks, ses propres stores locaux.

#État local aux remotes (recommandé par défaut)

La règle de base : chaque remote gère son propre état local. Le remote Catalogue gère son état de filtres, de pagination, de sélection de produit. Le remote Checkout gère son état de panier, d'adresse, de paiement. Cet isolement est une force — il réduit les bugs de régression cross-modules.

#Partage d'état minimal via props et callbacks

Pour les données que le shell doit partager avec les remotes (identité de l'utilisateur connecté, tenant ID, permissions, langue), le pattern le plus simple est l'injection via props :

// shell-app — injection du contexte utilisateur dans le remote
<ProductGrid
  userId={session.user.id}
  tenantId={session.tenant.id}
  locale={router.locale}
  onAddToCart={(productId) => cartActions.add(productId)}
/>

Ce pattern est prévisible, testable et ne crée pas de couplage implicite entre les modules.

#Shared state via module fédéré

Pour les cas où plusieurs remotes doivent partager un état dynamique (le panier visible dans le header du shell et dans le checkout remote), le shell peut exposer un store partagé comme module fédéré :

// shell expose son store cart comme module
exposes: {
  './useCartStore': './src/stores/cartStore',
}

Le remote Checkout importe et utilise shell/useCartStore directement. Ce pattern fonctionne mais crée un couplage runtime entre le shell et le remote — à utiliser avec parcimonie.

#Event Bus pour les communications asynchrones

Un Event Bus basé sur CustomEvent (ou mitt comme bibliothèque légère) permet des communications découplées : le remote Catalogue émet cart:item-added avec le produit en payload, le shell (ou tout autre abonné) réagit en mettant à jour le compteur du panier dans le header.

En 2026, les React Server Components complexifient légèrement cette question : les RSC ne peuvent pas écouter des événements DOM. La frontière client/serveur dans chaque micro-app doit être pensée explicitement pour ne pas créer de conflits avec les patterns de communication cross-apps.


#Performance : les pièges à éviter (bundle duplication, hydration, Core Web Vitals)

Les micro-frontends peuvent considérablement dégrader les performances si les pièges classiques ne sont pas anticipés. Voici les trois problèmes que Nehos rencontre systématiquement lors d'audits d'applications micro-frontend existantes.

#Piège 1 : duplication de bundle React

Sans configuration explicite du partage de dépendances dans Module Federation, chaque remote charge sa propre copie de React, ReactDOM et des bibliothèques communes. Sur 4 micro-apps utilisant React 18 + React Query + date-fns, la duplication peut peser 800 Ko à 1,2 Mo de JavaScript supplémentaire — déclenchant immédiatement une dégradation du LCP et du TBT.

La correction : déclarer singleton: true pour React, ReactDOM et toute dépendance partagée dans la config Module Federation. Le singleton force l'utilisation d'une instance unique partagée entre le host et tous les remotes.

shared: {
  react: { singleton: true, requiredVersion: '^18.3.0', eager: true },
  'react-dom': { singleton: true, requiredVersion: '^18.3.0', eager: true },
  'react-query': { singleton: true, requiredVersion: '^5.0.0' },
}

L'option eager: true sur React et ReactDOM force leur chargement dans le chunk initial plutôt qu'en lazy — évitant un flash de rendu lors de l'hydration.

#Piège 2 : hydration asynchrone et régression CLS

Les remotes chargés en lazy (via dynamic(() => import('remote/Component'))) génèrent un délai d'hydration visible pour l'utilisateur : le skeleton s'affiche, puis le composant réel apparaît et pousse le contenu environnant — déclenchant un Cumulative Layout Shift.

Corrections :

  • Utiliser des skeletons avec des dimensions fixes correspondant au composant remote attendu
  • Pré-allouer l'espace visuel avec min-height sur le conteneur du remote
  • Pour les composants above-the-fold, considérer le SSR du remote (possible avec @module-federation/nextjs-mf + configuration serveur)
  • Monitorer le CLS par micro-app avec des outils comme Vercel Speed Insights ou Sentry Performance

Pour une analyse complète des stratégies d'optimisation des Core Web Vitals sur Next.js, l'article dédié couvre les techniques avancées.

#Piège 3 : waterfalls de chargement en cascade

Le shell charge son JS → parse → exécute → découvre les remotes → charge les remotes JS → parse → exécute → affiche. Cette cascade peut ajouter 800 ms à 2 s de délai d'affichage perçu sur mobile.

Corrections :

  • <link rel="preload"> sur les remoteEntry.js des remotes critiques (above-the-fold)
  • Prefetch des remotes secondaires (<link rel="prefetch">) au moment du hover ou de l'interaction qui précède leur affichage
  • Configurer des Resource Hints dans le <Head> du shell pour les remotes prioritaires

Une architecture micro-frontend performante dans les Core Web Vitals nécessite de traiter le chargement des remotes avec le même niveau d'attention que l'optimisation des images ou du JavaScript first-party.


#Déploiement indépendant : Vercel, AWS CloudFront, Nginx proxy

Le déploiement indépendant est la raison d'être des micro-frontends. Sa mise en œuvre exige une infrastructure adaptée.

#Vercel : la solution la plus simple pour les équipes Next.js

Chaque micro-app est un projet Vercel distinct, avec sa propre URL de déploiement, son propre domaine de preview, sa propre pipeline CI/CD. Le shell référence les remotes via des variables d'environnement pointant vers les URLs Vercel.

# Variables d'environnement du shell sur Vercel
CATALOGUE_MFE_URL=https://catalogue-mfe.vercel.app
CHECKOUT_MFE_URL=https://checkout-mfe.vercel.app
DASHBOARD_MFE_URL=https://dashboard-mfe.vercel.app

Avantage : la Preview URL de chaque remote change à chaque déploiement. Le shell peut être configuré pour pointer vers une branche de preview spécifique pendant les tests d'intégration cross-teams. Vercel gère automatiquement l'invalidation de cache CDN à chaque déploiement.

#AWS CloudFront : contrôle maximal pour les architectures enterprise

Pour les projets avec des contraintes de souveraineté des données, de SLA contractuel ou de coût à grande échelle, AWS CloudFront offre un contrôle total :

# Routing CloudFront par micro-app
/catalogue/_next/*  → S3 bucket catalogue-mfe (invalidation par déploiement)
/checkout/_next/*   → S3 bucket checkout-mfe
/dashboard/_next/*  → S3 bucket dashboard-mfe
/*                  → EC2/ECS shell-app (ou Lambda@Edge)

La gestion du cache est critique : chaque déploiement d'un remote doit invalider les fichiers modifiés dans CloudFront (aws cloudfront create-invalidation --paths '/catalogue/_next/*'). Sans invalidation, le shell charge des bundles remote obsolètes.

#Nginx proxy pour les environnements on-premise

Pour les clients en datacenter privé ou en cloud souverain OVH/Scaleway, Nginx permet d'implémenter le routing micro-frontend :

# nginx.conf
upstream shell { server shell-app:3000; }
upstream catalogue { server catalogue-mfe:3001; }
upstream checkout { server checkout-mfe:3002; }

server {
  location /catalogue/_next/ { proxy_pass http://catalogue; }
  location /checkout/_next/  { proxy_pass http://checkout; }
  location /                  { proxy_pass http://shell; }
}

Chaque micro-app est un conteneur Docker indépendant, orchestré par Kubernetes ou Docker Compose. Les mises à jour rolling sont possibles par micro-app sans downtime du shell.

#Versioning des remotes et stratégie de rollback

En production, les remotes doivent être versionnés explicitement. Le shell ne doit jamais pointer vers latest — toujours vers une version précise validée en staging :

CATALOGUE_MFE_URL=https://catalogue-mfe.vercel.app/v2.4.1

En cas de régression après déploiement d'un remote, le rollback est immédiat : changer la variable d'environnement du shell vers la version précédente du remote, sans toucher au shell ni aux autres remotes. C'est l'un des bénéfices les plus tangibles de l'architecture — un rollback en 30 secondes sur un module isolé.


#Quand NE PAS faire du micro-frontend : les contre-indications pour PME/ETI

Après avoir décrit tout ce que les micro-frontends permettent de faire, c'est peut-être la section la plus utile de cet article.

La réalité de mes missions en 2025-2026 : sur 10 projets où la question des micro-frontends est posée, 7 n'en ont pas besoin. L'architecture ajoute une complexité réelle qui n'est justifiée que dans des conditions organisationnelles et techniques spécifiques.

#Contre-indication 1 : équipe frontend inférieure à 6 développeurs

Les micro-frontends sont une solution au problème de coordination entre équipes multiples. Si vous n'avez qu'une seule équipe frontend (même de 5 à 8 personnes), le problème n'existe pas. Un monorepo bien structuré avec Turborepo donne exactement les mêmes bénéfices d'isolation de code sans la complexité du chargement de remotes à runtime.

La règle pratique : en dessous de 3 équipes frontend indépendantes avec des roadmaps distinctes, un monorepo suffit.

#Contre-indication 2 : domaine métier non découpable

Les micro-frontends s'appuient sur un découpage de bounded contexts clair. Si les modules de votre application s'interconnectent fortement — si le Catalogue dépend du Checkout qui dépend du CRM qui modifie le Catalogue — le découpage en remotes isolés ne fait que déplacer la complexité de couplage du code vers les contrats inter-apps. Le résultat est souvent pire.

Avant d'envisager des micro-frontends, posez la question : «Peut-on déployer le module A sans redeployer le module B ?» Si la réponse est non 60 % du temps, l'architecture n'apportera pas le bénéfice attendu.

#Contre-indication 3 : startup ou application en phase de discovery

Dans les 12 à 18 premiers mois d'un produit, les frontières de domaine ne sont pas encore stabilisées. Les micro-frontends figent une architecture avant que vous sachiez où sont vraiment les frontières naturelles. La dette technique d'une mauvaise découpure est considérable — il faut parfois deux sprints complets pour fusionner deux remotes mal découpés.

La recommandation : démarrez en monolithe bien structuré. Quand les douleurs de coordination deviennent mesurables (builds bloquants, déploiements coordonnés pénibles, tests cross-modules instables), c'est le moment d'envisager l'extraction en remotes.

#Contre-indication 4 : absence de budget infrastructure

Maintenir 4 applications Next.js indépendantes au lieu d'une coûte 4x le budget infrastructure (CI/CD, monitoring, alerting, mise à jour des dépendances, gestion des incidents). Sur Vercel Pro, 4 projets distincts = 4 fois le quota de build minutes. Sur AWS, 4 fois les load balancers, health checks, et services associés.

Pour les PME et ETI dont l'infrastructure frontend est gérée par 1 à 2 personnes, ce surcoût opérationnel est souvent prohibitif. Un headless commerce B2B bien architecturé en Next.js monolithique bien structuré reste la recommandation Nehos pour les organisations de cette taille.

#Contre-indication 5 : absence d'expertise Module Federation en interne

Module Federation a une courbe d'apprentissage significative. Les erreurs de configuration (singletons mal configurés, circular dependencies, SSR/CSR mismatch) génèrent des bugs difficiles à diagnostiquer — les messages d'erreur sont souvent peu parlants et les stack traces traversent la frontière shell/remote.

Si l'équipe n'a jamais déployé Module Federation en production et n'a pas le budget pour un accompagnement technique initial (2 à 4 sprints de mise en place), le risque de sur-ingénierie est élevé. Dans ce cas, la refonte du site B2B en Next.js bien structuré est une décision d'architecture plus sûre et plus rentable.

#Le test des 5 questions

Avant de décider d'adopter une architecture micro-frontend, répondez honnêtement à ces 5 questions :

  1. Avez-vous au moins 3 équipes frontend avec des cycles de déploiement indépendants ?
  2. Votre domaine métier présente-t-il des bounded contexts clairement identifiables avec peu de dépendances transversales ?
  3. Les conflits de déploiement entre équipes représentent-ils une douleur mesurable aujourd'hui ?
  4. Votre équipe a-t-elle l'expertise Module Federation ou le budget pour l'acquérir ?
  5. Avez-vous le budget infrastructure pour maintenir N applications indépendantes ?

Si vous répondez non à 3 de ces 5 questions, les micro-frontends ne sont pas la bonne décision aujourd'hui. Revenez à cette checklist dans 12 mois — les conditions organisationnelles changent souvent plus vite que les architectures.

Questions & Réponses

Questions fréquentes sur les micro-frontends B2B

Un monorepo est une stratégie d'organisation de code : tout le code vit dans un même dépôt, découpé en packages (apps, libs). Chaque package a ses propres tests et sa propre pipeline CI, mais le déploiement reste coordonné — une même commande peut rebuilder et déployer plusieurs apps ensemble. Un micro-frontend va plus loin : chaque micro-app est déployée indépendamment à runtime, les bundles JavaScript sont chargés dynamiquement par le shell depuis des URLs distinctes. Les deux ne s'excluent pas — on peut avoir un monorepo Turborepo *et* des déploiements indépendants via Module Federation. En pratique, le monorepo seul suffit pour la majorité des projets sous 50 développeurs frontend. Les micro-frontends ajoutent la couche de découplage à runtime, utile uniquement quand les déploiements coordonnés deviennent un vrai goulot d'étranglement organisationnel.
Oui, avec quelques nuances importantes. Le plugin `@module-federation/nextjs-mf` (maintenu par la communauté Module Federation, version 8+) supporte Next.js 14 et 15 avec App Router. La compatibilité SSR des remotes est possible mais requiert une configuration supplémentaire côté remote (`isServer: true` dans la config) et une attention particulière à la frontière Server/Client Components — les remotes exposant des Server Components doivent être traités différemment des remotes purement client. Pour les projets démarrant en 2026, la recommandation Nehos est de tester la combinaison App Router + Module Federation sur un POC de 2 sprints avant de valider l'architecture pour la production, car le support des RSC dans les remotes reste en évolution active.
Non — l'authentification doit être centralisée dans le shell. Le shell gère la session (token JWT, refresh token, état d'authentification) et injecte les informations nécessaires dans chaque remote via props : `userId`, `tenantId`, `permissions`, `accessToken`. Les remotes ne gèrent pas directement les tokens et ne redirigent pas vers la page de login — ils délèguent au shell via un callback ou un événement. Cette centralisation évite des bugs de synchronisation de session (logout partiel, tokens expirés dans certains remotes mais pas d'autres) et simplifie l'audit de sécurité. Le shell est le seul composant qui interagit avec le service d'identité (Keycloak, Auth0, NextAuth.js).
Les micro-frontends ont un impact SEO potentiellement négatif si les remotes sont chargés uniquement côté client (CSR). Google peut indexer le JavaScript, mais le rendu côté serveur reste la meilleure garantie. La solution est de configurer le SSR des remotes critiques via `@module-federation/nextjs-mf` — les composants above-the-fold et les contenus importants pour le SEO sont rendus côté serveur dans le shell, les remotes sont récupérés comme des composants RSC ou via des fetch server-side. Pour les pages purement fonctionnelles (dashboard, espace client derrière login), le CSR est acceptable car ces pages ne sont pas indexées. La règle : toute page accessible aux crawlers (Google, Bing, et les LLMs pour la GEO) doit être rendue côté serveur dans le shell ou via SSR du remote.
Les tests en architecture micro-frontend s'organisent en trois niveaux. Premier niveau : les tests unitaires et d'intégration de chaque remote sont totalement indépendants — chaque remote est testé en isolation avec des mocks pour les dépendances cross-apps (Vitest + Testing Library). Deuxième niveau : les tests de contrat entre le shell et les remotes définissent le contrat d'interface (props exposées, événements émis) — ces contrats sont versionnés et vérifiés automatiquement dans la CI pour détecter les régressions de breaking changes. Troisième niveau : les tests end-to-end (Playwright, Cypress) testent les parcours utilisateur complets en chargeant le shell avec les remotes de staging. Ces E2E tests sont le filet de sécurité pour les flux critiques (checkout, login, création de commande) qui traversent plusieurs remotes.
Une migration bien conduite utilise le strangler fig pattern : on extrait progressivement des modules en remotes sans tout réécrire d'un coup. Pour une application Next.js de taille moyenne (50 à 150 composants par domaine, 3 à 5 domaines à extraire), le planning réaliste est le suivant. Phase 0 (2 à 4 semaines) : mise en place du shell Module Federation, configuration de l'infrastructure de déploiement indépendant, extraction du premier remote pilote sur le domaine le moins couplé. Phase 1 (4 à 8 semaines par remote) : extraction des remotes domaine par domaine, migration du design system en package partagé, mise en place des tests de contrat. Phase 2 (2 à 4 semaines) : stabilisation, monitoring en production, documentation de l'architecture pour les équipes. Total réaliste pour une application à 4 domaines : 6 à 10 mois. Nehos accompagne ces migrations avec un audit préalable d'architecture pour identifier les dépendances transversales et prioriser l'ordre d'extraction.
Réserver un audit