Resumen: Este artículo explica cómo configurar Module Federation en Next.js para compartir componentes entre aplicaciones en tiempo de ejecución y crear micro‑frontends desplegables de forma independiente.
Incluye pasos prácticos, ejemplos de configuración y código listo para copiar y adaptar en tus proyectos.
Introducción
Module Federation (a través del plugin de Webpack) permite compartir módulos entre aplicaciones en tiempo de ejecución en lugar de durante el build.
En Next.js esto se usa para convertir un frontend monolítico en varios micro‑frontends que se desarrollan y despliegan de forma independiente, manteniendo una experiencia de usuario unificada.
Prerrequisitos
- Node.js y entorno para ejecutar aplicaciones Next.js.
- Dos aplicaciones Next.js (por ejemplo: remote-app y host-app).
- El paquete de integración para Next.js:
@module-federation/nextjs-mf.
Desarrollo
Procedimiento
Lista de pasos resumidos para crear el flujo host/remote:
- Crear la aplicación remote y añadir el plugin de Module Federation.
- Configurar
next.config.jsen la remote para exponer componentes. - Crear los componentes que se van a exponer.
- Crear la aplicación host, añadir el plugin y configurar los remotes.
- Declarar tipos (si usas TypeScript) y consumir los componentes remotos con import dinámico y
ssr: false.
En las siguientes subsecciones se incluyen ejemplos mínimos de configuración y uso.
Ejemplos
Comandos iniciales para crear las aplicaciones (ejemplo):
npx create-next-app@latest remote-app --typescript --tailwind --app
cd remote-app
npm install @module-federation/nextjs-mf
npm run dev -- -p 3001
Lenguaje del código: Bash (bash)
Ejemplo: next.config.js de la aplicación remote (expone componentes):
const { NextFederationPlugin } = require('@module-federation/nextjs-mf');
module.exports = {
webpack(config, options) {
config.plugins.push(
new NextFederationPlugin({
name: 'remote_app',
filename: 'static/chunks/remoteEntry.js',
exposes: {
'./Button': './components/Button',
'./UserCard': './components/UserCard',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
})
);
return config;
},
};
Lenguaje del código: JavaScript (javascript)
Componente Button en TypeScript (remote/components/Button.tsx):
interface ButtonProps {
onClick?: () => void;
children: React.ReactNode;
variant?: 'primary' | 'secondary';
}
export default function Button({ onClick, children, variant = 'primary' }: ButtonProps) {
const baseClasses = 'px-4 py-2 rounded-md font-medium transition-colors';
const variantClasses = {
primary: 'bg-blue-500 text-white hover:bg-blue-600',
secondary: 'bg-gray-200 text-gray-800 hover:bg-gray-300',
};
return (
<button
onClick={onClick}
className={`${baseClasses} ${variantClasses[variant]}`}
>
{children}
</button>
);
}
Lenguaje del código: TypeScript (typescript)
Arrancar la remote en el puerto 3001:
npm run dev -- -p 3001
Lenguaje del código: Bash (bash)
Comandos y configuración para la aplicación host:
npx create-next-app@latest host-app --typescript --tailwind --app
cd host-app
npm install @module-federation/nextjs-mf
Lenguaje del código: Bash (bash)
next.config.js de la aplicación host (consume la remote):
const { NextFederationPlugin } = require('@module-federation/nextjs-mf');
module.exports = {
webpack(config, options) {
config.plugins.push(
new NextFederationPlugin({
name: 'host_app',
remotes: {
remote_app: 'remote_app@http://localhost:3001/_next/static/chunks/remoteEntry.js',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
})
);
return config;
},
};
Lenguaje del código: JavaScript (javascript)
Definiciones de tipos para TypeScript (types/remote-components.d.ts):
declare module 'remote_app/Button' {
interface ButtonProps {
onClick?: () => void;
children: React.ReactNode;
variant?: 'primary' | 'secondary';
}
const Button: React.ComponentType<ButtonProps>;
export default Button;
}
declare module 'remote_app/UserCard' {
interface User {
id: string;
name: string;
email: string;
avatar?: string;
}
interface UserCardProps {
user: User;
onEdit?: () => void;
}
const UserCard: React.ComponentType<UserCardProps>;
export default UserCard;
}
Lenguaje del código: TypeScript (typescript)
Consumo dinámico de componentes remotos en app/page.tsx (host):
'use client';
import { Suspense, useState } from 'react';
import dynamic from 'next/dynamic';
const RemoteButton = dynamic(() => import('remote_app/Button'), {
ssr: false,
});
const RemoteUserCard = dynamic(() => import('remote_app/UserCard'), {
ssr: false,
});
export default function Home() {
const [message, setMessage] = useState('');
const sampleUser = {
id: '1',
name: 'John Doe',
email: '[email protected]',
};
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold text-center mb-8">
Module Federation Demo
</h1>
<div className="max-w-2xl mx-auto space-y-8">
<div className="text-center">
<h2 className="text-xl font-semibold mb-4">Remote Button Component</h2>
<Suspense fallback=<>Loading button...</>>
<RemoteButton
onClick={() => setMessage('Hello from remote button!')}
variant="primary"
>
Click Me (Remote)
</RemoteButton>
</Suspense>
{message && (
<p className="mt-4 text-green-600 font-medium">{message}</p>
)}
</div>
<div className="text-center">
<h2 className="text-xl font-semibold mb-4">Remote UserCard Component</h2>
<Suspense fallback=<>Loading user card...</>>
<div className="flex justify-center">
<RemoteUserCard
user={sampleUser}
onEdit={() => alert('Edit clicked!')}
/>
</div>
</Suspense>
</div>
</div>
</div>
);
}
Lenguaje del código: TypeScript (typescript)
Arrancar la host en otro puerto (ejemplo 3000):
npm run dev -- -p 3000
Lenguaje del código: Bash (bash)
Nota práctica: siempre usar import dinámico con ssr: false y envolver en Suspense para evitar problemas con SSR.
Ejemplo de manejo de URL remota entre entornos (ejemplo tomado como referencia):
const remoteUrl = process.env.NODE_ENV === 'production'
? 'https://your-host-app.vercel.app/_next/static/chunks/remoteEntry.js'
: 'http://localhost:3000/_next/static/chunks/remoteEntry.js';
Lenguaje del código: JavaScript (javascript)
Checklist
- Usar import dinámico con
ssr: falsey envolver enSuspense. - Compartir React y react-dom como singleton en la configuración de Module Federation.
- Declarar tipos .d.ts para los módulos federados si usas TypeScript.
- Probar en desarrollo con URLs locales y configurar la URL remota para producción mediante variables de entorno.
- Verificar que no se carguen múltiples instancias de React (comportamientos extraños en hooks).
Estos pasos cubren las causas más comunes de errores y facilitan el diagnóstico durante la integración.
Conclusión
Module Federation en Next.js permite compartir componentes entre aplicaciones sin recompilar todo el ecosistema, lo que facilita equipos independientes y despliegues más rápidos.
No obstante, añade complejidad: obliga a diseñar componentes para renderizado en cliente y a gestionar dependencias compartidas con cuidado.
Si tu equipo gestiona varias aplicaciones relacionadas o necesitas un sistema de diseño compartido en tiempo real, Module Federation es una herramienta que vale la pena probar y dominar.

Deja un comentario