Arquitectura de Microfrontends con Module Federation y Next.js para Sistemas Empresariales

A medida que las organizaciones crecen y sus sistemas web corporativos incorporan múltiples módulos (CRM, facturación, e-commerce, portal de soporte y analítica), mantener una única base de código monolítica genera fricción entre equipos, despliegues lentos y riesgo de roturas en cascada. En este artículo analizamos la arquitectura de Microfrontends con Module Federation en el ecosistema de Next.js y TypeScript.

¿Qué son los Microfrontends y cuándo utilizarlos?#
Los microfrontends extienden los principios de los microservicios a la capa de interfaz de usuario. En lugar de compilar una sola aplicación gigantesca, dividimos la plataforma en aplicaciones web independientes (Remotes) que son orquestadas dinámicamente en tiempo de ejecución por una aplicación anfitriona (Host / Shell).
Criterios para adoptar Microfrontends:#
- Múltiples equipos autónomos: Diferentes squads desarrollando características en paralelo sin bloquearse mutuamente.
- Despliegues independientes: Actualizar el módulo de facturación sin necesidad de re-compilar ni desplegar el portal de clientes.
- Aislamiento de fallos: Un error en un módulo secundario no bloquea la navegación general de la plataforma.
Arquitectura del Ecosistema Federado#
+----------------------------------+
| HOST / SHELL APP |
| (Next.js: Auth, Layout & Nav) |
+----------------------------------+
| |
+----------------+ +----------------+
| |
v v
+----------------------------------+ +----------------------------------+
| REMOTE A: DASHBOARD & CRM | | REMOTE B: FACTURACIÓN & PAGOS |
| (Next.js / Module Fed) | | (Next.js / Module Fed) |
+----------------------------------+ +----------------------------------+
\ /
+-------------------+-------------------+
|
v
+----------------------------------+
| SHARED LIBRARIES / STORE |
| (React, Zustand, UI Design System)|
+----------------------------------+
1. Configuración del Módulo Remoto (remote-billing)#
En la aplicación remota encargada del módulo de facturación, configuramos @module-federation/nextjs-mf en next.config.js para exponer los componentes deseados:
// next.config.js (Remote App: remote-billing)
const { NextFederationPlugin } = require('@module-federation/nextjs-mf');
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack(config, options) {
if (!options.isServer) {
config.plugins.push(
new NextFederationPlugin({
name: 'remoteBilling',
filename: 'static/chunks/remoteEntry.js',
exposes: {
'./BillingDashboard': './src/components/BillingDashboard.tsx',
'./InvoiceHistoryTable': './src/components/InvoiceHistoryTable.tsx',
},
shared: {
react: { singleton: true, requiredVersion: false },
'react-dom': { singleton: true, requiredVersion: false },
zustand: { singleton: true, requiredVersion: false },
},
})
);
}
return config;
},
};
module.exports = nextConfig;
2. Configuración del Host / Shell (host-enterprise)#
En la aplicación anfitriona, registramos los puntos de entrada de cada aplicación remota:
// next.config.js (Host App: host-enterprise)
const { NextFederationPlugin } = require('@module-federation/nextjs-mf');
const BILLING_APP_URL =
process.env.NODE_ENV === 'production'
? 'https://billing.empresa.com'
: 'http://localhost:3001';
/** @type {import('next').NextConfig} */
const nextConfig = {
webpack(config, options) {
if (!options.isServer) {
config.plugins.push(
new NextFederationPlugin({
name: 'hostEnterprise',
remotes: {
remoteBilling: `remoteBilling@${BILLING_APP_URL}/_next/static/chunks/remoteEntry.js`,
},
shared: {
react: { singleton: true, requiredVersion: false },
'react-dom': { singleton: true, requiredVersion: false },
zustand: { singleton: true, requiredVersion: false },
},
})
);
}
return config;
},
};
module.exports = nextConfig;
3. Consumo Dinámico de Componentes Remotos con React Suspense#
En el Host, consumimos el componente federado utilizando dynamic de Next.js y un ErrorBoundary para asegurar una experiencia fluida:
// src/app/dashboard/facturacion/page.tsx (Host App)
'use client';
import React, { Suspense } from 'react';
import dynamic from 'next/dynamic';
// Importación dinámica del microfrontend remoto
const RemoteBillingDashboard = dynamic(
() => import('remoteBilling/BillingDashboard'),
{
ssr: false,
loading: () => (
<div className="p-8 flex items-center justify-center space-x-3 text-cyan-400">
<span className="w-5 h-5 border-2 border-cyan-400 border-t-transparent rounded-full animate-spin"></span>
<p>Cargando módulo de Facturación Empresarial...</p>
</div>
),
}
);
export default function BillingPage() {
return (
<div className="space-y-6">
<header className="border-b border-slate-800 pb-4">
<h1 className="text-2xl font-bold text-white">Centro Financiero y Facturación</h1>
<p className="text-sm text-slate-400">Módulo federado independiente de alta concurrencia</p>
</header>
<Suspense fallback={<div>Iniciando microfrontend...</div>}>
<RemoteBillingDashboard companyId="CORP-9821" theme="dark" />
</Suspense>
</div>
);
}
4. Comunicación y Estado Compartido entre Microfrontends#
Para sincronizar datos globales como la sesión de usuario autenticado o notificaciones sin acoplar los bundles, utilizamos un bus de eventos o un store liviano con Zustand federado como singleton:
// src/store/authStore.ts (Compartido como singleton)
import { create } from 'zustand';
interface UserSession {
userId: string;
name: string;
role: 'admin' | 'billing_manager' | 'viewer';
token: string;
}
interface AuthState {
session: UserSession | null;
setSession: (session: UserSession | null) => void;
}
export const useAuthStore = create<AuthState>((set) => ({
session: null,
setSession: (session) => set({ session }),
}));
Buenas Prácticas y Lecciones Aprendidas#
- Versionado Semántico en Contratos de Props: Trata las props de los componentes exportados como si fueran endpoints de una API pública.
- Monitoreo de Bundles Compartidos: Asegura que dependencias pesadas como
react,react-domylucide-reacttengan la directivasingleton: truepara evitar duplicación de memoria en el navegador. - Estrategia de Fallback Resiliente: Si el microfrontend remoto no responde debido a una caída de servidor, la app anfitriona debe mostrar una alerta elegante con botón de reintento.
¿Estás planificando modernizar tu arquitectura de software, migrar un monolito o construir una plataforma SaaS escalable? Consulta nuestro catálogo de Servicios de Arquitectura y Software o contáctanos para asesorar a tu equipo.
¿Te gustaría profundizar en estos temas?
Aprende sobre desarrollo de software, apps a medida, automatizaciones con N8N, Next.js y Cloud con casos reales.


