Los micro frontends llevan la idea de los microservicios a la capa del frontend. En lugar de construir una única aplicación monolítica, el frontend se descompone en aplicaciones más pequeñas e independientes que se desarrollan, prueban y despliegan por separado. Cada micro frontend es dueño de un dominio de negocio concreto y puede construirse con otra tecnología, por otro equipo y con otro ritmo de publicación.
La arquitectura nació de las mismas presiones que impulsaron los microservicios en el backend. A medida que las aplicaciones web ganaban complejidad, los frontends monolíticos se volvieron difíciles de mantener, lentos de construir y arriesgados de desplegar. Un solo cambio en cualquier parte del código obligaba a reconstruir y volver a desplegar toda la aplicación, frenando a los equipos y creando fricción entre grupos que querían moverse a distinta velocidad.
¿Qué son los micro frontends?
Una arquitectura de micro frontends divide una aplicación web en rebanadas funcionales, cada una a cargo de un equipo independiente. El equipo responde de todas las capas de su rebanada: los componentes de interfaz, la lógica de negocio, la obtención de datos y la integración con el backend. El usuario ve una aplicación única y coherente, pero por dentro está compuesta por varias aplicaciones pequeñas que corren en la misma ventana del navegador.
Esta descomposición sigue los principios del diseño guiado por el dominio. Cada micro frontend corresponde a un contexto delimitado: una frontera lógica alrededor de una capacidad de negocio concreta. El proceso de pago, el catálogo de productos, el perfil del usuario y la búsqueda pueden ser micro frontends distintos, a cargo de equipos distintos.
La diferencia clave entre micro frontends y simplemente partir el código en módulos es que los micro frontends son independientes en tiempo de construcción y de despliegue. Cada uno tiene su propia canalización, su propio repositorio, sus propias pruebas y su propio calendario. Esa independencia es lo que da a la arquitectura sus ventajas y también lo que crea sus dificultades.
Un micro frontend no es una biblioteca de componentes ni un conjunto de utilidades compartidas. Es una aplicación autónoma que se compone en tiempo de ejecución dentro de una aplicación mayor. Esa distinción es esencial para entender tanto la potencia como el coste de la arquitectura.
Module Federation con Webpack 5
Module Federation es el enfoque más extendido en los ecosistemas de React y Angular. Introducido en Webpack 5, permite que una aplicación de JavaScript cargue código de otra aplicación en tiempo de ejecución. El código cargado corre en el contexto de la aplicación anfitriona y comparte dependencias para no duplicar bibliotecas como React o Vue.
Funciona exponiendo módulos concretos desde una aplicación remota e importándolos en la anfitriona. La remota declara qué módulos están disponibles y la anfitriona los referencia como si fueran importaciones locales. Webpack se encarga de la carga asíncrona, de eliminar dependencias duplicadas y de resolver versiones en tiempo de construcción.
El mecanismo de dependencias compartidas es su característica más importante. Cuando anfitriona y remota usan la misma biblioteca, Webpack asegura que solo se cargue una copia en el navegador. Así se evita la degradación que supondría cargar varias copias de React, Lodash u otras bibliotecas grandes. El patrón de instancia única garantiza además que el estado compartido —un almacén de Redux o un contexto de React— se comparta de verdad entre micro frontends.
// webpack.config.js - Remote application exposing a module
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "checkout",
filename: "remoteEntry.js",
exposes: {
"./CheckoutApp": "./src/bootstrap",
},
shared: {
react: { singleton: true, requiredVersion: "^18.0.0" },
"react-dom": { singleton: true, requiredVersion: "^18.0.0" },
},
}),
],
};
// webpack.config.js - Host application consuming the remote
const { ModuleFederationPlugin } = require("webpack").container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "shell",
remotes: {
checkout: "checkout@http://localhost:3001/remoteEntry.js",
},
shared: {
react: { singleton: true, requiredVersion: "^18.0.0" },
"react-dom": { singleton: true, requiredVersion: "^18.0.0" },
},
}),
],
};
// Lazy loading the remote module in the host
const CheckoutApp = React.lazy(() => import("checkout/CheckoutApp"));
function Shell() {
return (
<Suspense fallback={<Spinner />}>
<CheckoutApp />
</Suspense>
);
}La anfitriona carga el archivo de entrada remoto cuando el usuario llega a una ruta que necesita el micro frontend de pago. Ese archivo es un pequeño JavaScript que Webpack genera solo: contiene un índice de todos los módulos expuestos y su ubicación. Cuando la anfitriona pide un módulo concreto, Webpack descarga el fragmento correspondiente y lo ejecuta en el contexto de dependencias compartidas.
Una consideración importante es que anfitriona y remota deben coincidir en las versiones de las dependencias compartidas. Si la remota necesita React 18.2 y la anfitriona solo tiene React 18.0, la instancia única fallará salvo que las versiones sean compatibles. El campo requiredVersion admite rangos de versionado semántico, lo que da margen y a la vez protege frente a cambios rompedores.
Integración mediante iframes
Antes de Module Federation y otras técnicas modernas, los iframes eran el enfoque original. Un iframe incrusta un documento HTML completamente independiente dentro de una página. Ese documento tiene su propio contexto de JavaScript, su propio ámbito de CSS y su propio árbol del DOM. Ese aislamiento es a la vez la fuerza y la debilidad del método.
Los iframes ofrecen las garantías de aislamiento más fuertes de todas las técnicas. No hay riesgo de conflictos de CSS porque cada uno tiene su documento. No hay colisiones de JavaScript porque cada uno tiene su ámbito global. Ningún micro frontend puede alterar por accidente el estado de otro, porque los árboles del DOM están completamente separados. Una fuga de memoria en uno no puede tumbar a otro.
Estas garantías cuestan caro. Los iframes pesan. Cada uno carga un documento HTML completo, con todos sus recursos de CSS y JavaScript. El navegador trata a cada uno como un contexto de navegación separado, lo que implica más memoria, más peticiones de red y más trabajo de pintado. Si incrustas diez micro frontends en iframes, el navegador carga en la práctica once páginas.
La comunicación entre un iframe y su página exige la interfaz postMessage, que es asíncrona y se limita a datos serializables. No es posible pasar funciones, instancias de clase ni referencias al DOM a través de la frontera. Esto hace que los iframes no sirvan para micro frontends que necesitan integración estrecha: por ejemplo, un formulario de pago que necesita el estado del carrito de la página padre.
La accesibilidad es otra preocupación. Los lectores de pantalla y otras tecnologías de apoyo suelen tener problemas con contextos de navegación anidados. La navegación por teclado entre fronteras de iframe puede ser inconsistente. La búsqueda dentro de la página no cruza esas fronteras, y el historial trata cada navegación dentro de un iframe como una sesión aparte.
Los iframes encajan mejor para incrustar contenido de terceros, donde el aislamiento es lo primero y la integración es mínima. Son mala elección para componer una experiencia coherente en la que los micro frontends deben compartir estado, coordinar la navegación o formar una superficie visual unificada.
Single-spa y otros marcos de orquestación
Single-spa es un marco de JavaScript para orquestar varios micro frontends en una sola página. Gestiona el ciclo de vida de cada uno: los monta cuando el usuario llega a una ruta que los necesita, los desmonta cuando se va y mantiene en memoria los que no se usan para volver a montarlos deprisa. Es agnóstico respecto al marco y admite React, Angular, Vue, Svelte y JavaScript sin marco.
Cada micro frontend se registra en single-spa como una aplicación con funciones de ciclo de vida: bootstrap, mount, unmount y, opcionalmente, update. La raíz de single-spa controla el enrutado y decide qué aplicaciones están activas según patrones de URL. Cuando la URL coincide con la función de actividad de una aplicación registrada, single-spa la monta y desmonta las que ya no están activas.
Single-spa resuelve uno de los problemas más duros: la convivencia entre marcos. Cuando dos micro frontends se construyen con versiones distintas del mismo marco, o con marcos completamente diferentes, single-spa se asegura de que puedan coexistir en la misma página sin conflictos. Lo consigue interviniendo en los enganches de ciclo de vida del marco y aislando el estado global de cada aplicación.
Otros enfoques son Piral, con un modelo de complementos donde los micro frontends se cargan como módulos desde un servicio de distribución, y Open Components, centrado en la composición en el servidor. También está la vía de los componentes web, donde cada micro frontend se envuelve en un elemento propio y se registra en la interfaz de elementos personalizados del navegador. Los componentes web aportan delimitación nativa para HTML, CSS y JavaScript, y se pueden componer de forma declarativa en plantillas HTML.
La elección depende de tu pila tecnológica, de la estructura de tus equipos y de tus requisitos de rendimiento. Module Federation es la mejor opción para equipos que ya usan Webpack. Single-spa tiene sentido en arquitecturas mixtas donde cada micro frontend usa un marco distinto. Los componentes web encajan en organizaciones que quieren imponer fronteras neutrales respecto al marco. Los iframes solo son apropiados para incrustar contenido de terceros.
Bibliotecas de componentes y sistemas de diseño compartidos
Una preocupación habitual es la falta de coherencia visual. Si cada equipo construye su interfaz por su cuenta, el usuario puede ver botones, tipografías y patrones de maquetación distintos según avanza por la aplicación. La solución es una biblioteca de componentes o un sistema de diseño compartido que todos los micro frontends consuman.
La biblioteca compartida suele incluir componentes de presentación: botones, campos, ventanas modales y elementos de navegación. Son puramente visuales y no contienen lógica de negocio. Aceptan propiedades para variaciones de estilo, etiquetas y manejadores de eventos, pero no obtienen datos, no gestionan estado ni implementan comportamiento propio del dominio. Esa separación mantiene la biblioteca estable y evita que se convierta en un cuello de botella para la velocidad de los equipos.
Versionarla exige planificación. Si se publica como paquete de npm, cada micro frontend fija una versión y actualiza a su ritmo. Eso da autonomía, pero puede producir deriva de versiones, donde el mismo componente se ve distinto en distintos micro frontends. Una batería de pruebas de regresión visual para la biblioteca ayuda a detectar esas inconsistencias antes de llegar a producción.
Otra opción es servir el sistema de diseño como dependencia en tiempo de ejecución. La biblioteca se despliega como aplicación autónoma y cada micro frontend la carga al arrancar. Así todos usan siempre la última versión de cada componente y desaparece la deriva. A cambio, actualizar el sistema exige un despliegue y cualquier cambio rompedor afecta a todos los micro frontends a la vez.
Los tokens de diseño como mínimo común denominador
Los tokens de diseño —valores con nombre para colores, espaciados, tipografía y sombras— son una alternativa más ligera que una biblioteca completa. Cada micro frontend implementa sus propios componentes pero referencia el mismo conjunto de tokens. Eso da libertad de implementación manteniendo la coherencia visual. Los tokens pueden distribuirse como propiedades personalizadas de CSS, fáciles de sobreescribir y que no exigen herramienta de construcción alguna.
Comunicación entre micro frontends
Los micro frontends necesitan comunicarse. El de pago necesita saber qué añadió el usuario al carrito en el del catálogo. El de la cabecera necesita actualizar el aviso cuando el de notificaciones recibe una nueva. El de acceso necesita informar a todos los demás cuando el usuario entra o sale.
El mecanismo más sencillo es un bus de eventos compartido. Cada micro frontend publica eventos en un canal global y se suscribe a los de los demás. El bus suele implementarse como un emisor de eventos colgado del objeto window o inyectado por la cáscara. Los eventos llevan un tipo y una carga, y quienes se suscriben filtran por tipo.
// Shared event bus - shell application
// Each micro frontend receives this bus as part of its initialization.
type BusEvent = {
type: string;
payload: unknown;
};
type Listener = (event: BusEvent) => void;
class EventBus {
private listeners: Map<string, Listener[]> = new Map();
on(type: string, listener: Listener): () => void {
if (!this.listeners.has(type)) {
this.listeners.set(type, []);
}
this.listeners.get(type)!.push(listener);
return () => this.off(type, listener);
}
off(type: string, listener: Listener): void {
const listeners = this.listeners.get(type);
if (listeners) {
this.listeners.set(
type,
listeners.filter((l) => l !== listener)
);
}
}
emit(type: string, payload: unknown): void {
this.listeners.get(type)?.forEach((listener) => {
listener({ type, payload });
});
}
}
// Usage in a micro frontend
export function init(bus: EventBus) {
bus.on("item:added-to-cart", (event) => {
updateCartBadge(event.payload.quantity);
});
bus.emit("user:logged-in", { userId: "abc-123", name: "Jane" });
}Para necesidades más complejas, un almacén de estado compartido suele ser mejor que un bus de eventos. Un almacén de Redux o Zustand que viva en la cáscara puede inyectarse en cada micro frontend. Cada uno lee de él el estado que cruza dominios y escribe en su propio almacén local el estado específico de su dominio. Este patrón mantiene el acoplamiento flojo y a la vez ofrece una única fuente de verdad para datos compartidos como el usuario actual, el contenido del carrito o la navegación activa.
La capa de comunicación debe diseñarse y documentarse de forma explícita. Los equipos tienen que acordar nombres de eventos, formas de la carga y la frontera entre estado compartido y estado local. Sin ese acuerdo, los micro frontends desarrollan dependencias implícitas del estado interno ajeno, creando un monolito distribuido con toda la complejidad de los micro frontends y ninguna de sus ventajas.
Estrategias de enrutado
El enrutado en esta arquitectura debe responder a dos preguntas: ¿qué micro frontend es dueño de la ruta actual? y ¿cómo funciona la navegación entre ellos? Las respuestas dependen de si usas un enrutador centralizado en la cáscara, un enfoque distribuido o una estrategia mixta.
En el enrutado centralizado, una aplicación cáscara posee el enrutador de primer nivel. Define el mapa de rutas, determina qué micro frontend montar para cada patrón de URL y le pasa los parámetros. Cada micro frontend tiene su propio enrutador interno para navegar dentro de su dominio. La cáscara gestiona la navegación entre dominios; los micro frontends, la interna.
En el enrutado distribuido, cada micro frontend es dueño de sus rutas. La cáscara sigue gestionando la correspondencia general entre URL y micro frontend, pero cada uno administra por su cuenta sus subrutas y su navegación interna. Una biblioteca de navegación en la cáscara coordina los cambios de historial y garantiza que la barra de direcciones refleje el estado de toda la aplicación, no solo del micro frontend activo.
En el enrutado por eventos, la navegación se coordina a través del bus. Cuando un micro frontend necesita ir a una ruta que pertenece a otro, emite un evento de navegación. La cáscara lo escucha y realiza el cambio, lo que provoca que el destino se monte. Así las cuestiones de enrutado quedan fuera de los micro frontends y la lógica de navegación se centraliza en la cáscara.
- Enrutado centralizado: la cáscara posee el mapa de rutas y los micro frontends solo gestionan su navegación interna. Ideal para equipos pequeños y fronteras de dominio sencillas.
- Enrutado distribuido: cada micro frontend administra sus subrutas. Ideal para equipos grandes con dominios claramente separados.
- Enrutado por eventos: la navegación se coordina mediante un bus compartido. Ideal para arquitecturas mixtas con distintos marcos.
- Enrutado híbrido: la cáscara gestiona las rutas de dominio de primer nivel y los micro frontends las subrutas. Ideal para la mayoría de aplicaciones en producción.
Despliegue y versionado
La independencia en el despliegue es la motivación principal para adoptar micro frontends. Cada equipo debería poder desplegar el suyo sin coordinarse con nadie y sin afectar a la estabilidad del conjunto. Lograrlo exige diseñar con cuidado la canalización, la estrategia de alojamiento y el esquema de versiones.
El modelo más sencillo es el alojamiento separado. Cada micro frontend se despliega en su propia dirección o en su propio depósito de almacenamiento. La cáscara lo carga desde allí en tiempo de ejecución. Este modelo da la máxima independencia, porque cada equipo controla su infraestructura, su canalización y su estrategia de reversión. La cáscara no necesita volver a desplegarse cuando un micro frontend se actualiza, porque carga dinámicamente la última versión.
El alojamiento separado trae un reto nuevo: coordinar despliegues para preservar la compatibilidad hacia atrás. Si el micro frontend de pago espera cierta forma de propiedades desde la cáscara y el siguiente despliegue de la cáscara cambia esa forma, el de pago se romperá hasta que también se actualice. La solución es versionar el contrato de integración —normalmente las propiedades que la cáscara pasa a cada micro frontend— y seguir versionado semántico para los cambios rompedores.
Los despliegues graduales y las pruebas canario son más fáciles aquí, porque cada micro frontend se despliega por separado. Un equipo puede publicar una versión nueva para el cinco por ciento de los usuarios, vigilar las tasas de error y las métricas de rendimiento, y aumentar el alcance poco a poco si todo va bien. Si aparece un problema, revierte solo su micro frontend sin tocar el resto de la aplicación.
Fijar la versión desde la cáscara es la salida de emergencia. Si un despliegue introduce un cambio rompedor que las pruebas no detectaron, la cáscara puede fijar la versión anterior y restaurar la estabilidad mientras el equipo arregla el problema. Ese mecanismo suele ser un archivo de configuración o una variable de entorno que asocia cada micro frontend a una versión concreta ya desplegada.
Monorepo frente a repositorios separados
La estructura de repositorios para micro frontends es un tema discutido en la comunidad. Los argumentos a favor del monorepo y los de los repositorios separados tienen mérito, y la elección correcta depende del tamaño del equipo, la madurez de la organización y las preferencias de herramientas.
Un monorepo guarda todos los micro frontends en un repositorio, organizados por directorios. Cada uno tiene su package.json, su configuración de construcción y su carpeta. Este enfoque usa herramientas como Turborepo, Nx, Lerna o los espacios de trabajo de pnpm para gestionar dependencias, ejecutar construcciones y orquestar tareas entre micro frontends.
- La configuración compartida de herramientas es sencilla: un solo ESLint, un solo TypeScript, un solo Prettier para todos.
- Las refactorizaciones transversales son más simples porque el código de todos está en un mismo sitio.
- La gestión de dependencias se centraliza, reduciendo el riesgo de versiones desalineadas.
- Son posibles los commits atómicos entre micro frontends cuando un cambio toca varios dominios.
El enfoque de varios repositorios pone cada micro frontend en el suyo, con su canalización y su configuración. Los equipos tienen plena autonomía sobre su pila y su proceso de publicación. Un equipo que quiera migrar de React a Preact puede hacerlo sin coordinarse con nadie, siempre que su micro frontend siga apareciendo correctamente en la cáscara.
- Los equipos tienen autonomía completa sobre su flujo de trabajo y sus herramientas.
- El repositorio se mantiene pequeño, con clonados rápidos y canalizaciones eficientes.
- No hacen falta herramientas especiales de monorepo: bastan los flujos habituales de Git y los registros de npm.
- Un cambio rompedor en un micro frontend no puede tumbar la construcción de otro.
La tendencia del sector se inclina hacia los monorepos, sobre todo en organizaciones que comparten sistema de diseño o utilidades. El coste operativo de coordinar cambios entre varios repositorios suele pesar más que la autonomía ganada, especialmente en equipos que ya trabajan juntos y con pilas parecidas. Aun así, para organizaciones con equipos dispersos que usan marcos distintos, los repositorios separados siguen siendo mejor opción.
Consideraciones de rendimiento
Los micro frontends traen consigo un sobrecoste de rendimiento frente a una aplicación monolítica. Cada uno carga su propio paquete de JavaScript, su propio CSS y, posiblemente, su propio entorno de ejecución del marco. El navegador debe descargar, analizar y ejecutar más código. Los bytes totales aumentan y el tiempo hasta que la página es usable en la primera carga se alarga.
El mecanismo de dependencias compartidas de Module Federation mitiga ese coste al garantizar que las bibliotecas se carguen una sola vez. Pero el código de aplicación —componentes, utilidades y lógica de negocio de cada micro frontend— no se comparte. Si el usuario recorre tres micro frontends distintos en una sesión, descarga el código de los tres, aunque solo interactúe con uno.
Partir el código dentro de cada micro frontend es imprescindible. Cada uno debería cargar de forma diferida sus rutas, sus componentes pesados y sus bibliotecas de terceros. Un micro frontend de panel de administración que incluya una biblioteca de gráficos no debería cargarla hasta que el usuario llegue a una página que dibuje un gráfico. Es la misma práctica que en aplicaciones monolíticas, aplicada dentro de cada frontera.
La precarga es una optimización valiosa. Cuando el usuario entra en una ruta del micro frontend de pago, la cáscara puede prever que a continuación irá al de confirmación del pedido y empezar a descargar sus recursos en segundo plano. Esa estrategia debe basarse en datos reales de comportamiento, no en suposiciones sobre patrones de navegación.
Hay que proteger la ruta crítica de pintado. La cáscara debería aparecer tan rápido como una aplicación monolítica, lo que significa que debe ser ligera: poco JavaScript, poco CSS, pocas dependencias. La cáscara responde del primer pintado, y los micro frontends lentos no deben retrasarlo. Cada uno debería cargarse de forma asíncrona y mostrar un estado de carga hasta estar listo.
Los presupuestos de rendimiento deben fijarse por micro frontend, no solo para el conjunto. Cada equipo debe conocer el tamaño máximo de su paquete, el tiempo máximo hasta ser usable y la huella máxima de memoria. Incumplirlos debería hacer fallar la canalización, igual que ocurriría en una aplicación monolítica.
Probar micro frontends
Probar esta arquitectura exige hacerlo en tres niveles: cada micro frontend aislado, la integración entre ellos y la aplicación compuesta en conjunto. Cada nivel tiene sus herramientas, sus objetivos y sus responsables.
Las pruebas unitarias y de componentes dentro de cada micro frontend siguen los mismos patrones que cualquier otra aplicación. Cada equipo prueba el suyo y las pruebas corren en su propia canalización. La única diferencia es que conviene probar asumiendo que la cáscara y los demás micro frontends son poco fiables: comprobar que el propio se degrada con elegancia cuando la cáscara entrega propiedades inesperadas o cuando un evento no llega.
La integración es el nivel más difícil. La prueba debe cargar la cáscara y varios micro frontends a la vez, simular interacciones que cruzan fronteras y verificar que el comportamiento compuesto es correcto. Herramientas como Cypress y Playwright brillan aquí porque corren en un navegador real y pueden manejar la aplicación completa.
Una estrategia eficaz es mantener un despliegue parecido al de producción en un entorno de pruebas, con cada micro frontend en su propia dirección y la cáscara configurada para cargarlos. La batería corre contra ese despliegue y recorre trayectos reales que cruzan fronteras. Así aparecen problemas invisibles en pruebas aisladas: errores de sincronización cuando un micro frontend aún no ha terminado de inicializarse y otro intenta comunicarse con él, o regresiones de estilo cuando un cambio de CSS en uno altera la maquetación de otro.
Las pruebas de regresión visual son especialmente importantes aquí. El sistema de diseño compartido debería tener su propia batería. Cada micro frontend debería tener las suyas para sus páginas. Y la aplicación compuesta debería tenerlas para los trayectos críticos. Herramientas como Percy, Chromatic o Loki se integran en la canalización y detectan las regresiones automáticamente.
Cuándo NO usar micro frontends
Los micro frontends no son la arquitectura adecuada para todo proyecto. La complejidad que añaden —coste operativo, coste de rendimiento, necesidad de coordinación y dificultad para depurar— solo se justifica por necesidades organizativas concretas. Aplicarlos a un proyecto que no los necesita genera fricción y ralentiza el desarrollo sin beneficio alguno.
Un equipo pequeño que construye una sola aplicación no los necesita. La arquitectura está pensada para organizaciones con varios equipos, cada uno responsable de un dominio distinto. Si todo tu frontend lo pueden construir tres o cuatro personas, una aplicación monolítica con módulos bien organizados será más productiva, más rápida de construir y más fácil de mantener.
Una aplicación con dominios muy acoplados es mala candidata. Si cada funcionalidad interactúa con todas las demás —si catálogo, carrito y pago están tan entrelazados que no se pueden separar con limpieza—, dividirlos te obligará a construir capas de comunicación complejas que imiten el acceso directo que tenías en el monolito. Ese es el antipatrón del monolito distribuido.
Una organización sin madurez operativa lo pasará mal. La arquitectura exige buenas prácticas de operaciones, pruebas automatizadas, monitorización y respuesta a incidencias. Cada equipo debe poder desplegar por su cuenta y revertir deprisa. Si tu organización aún no ha invertido en eso, hacerlo en el contexto de una aplicación monolítica es mejor inversión que adoptar micro frontends.
Las aplicaciones críticas en rendimiento, con requisitos estrictos de tiempo de carga, quizá no toleren este sobrecoste. Si cada milisegundo cuenta —por ejemplo, en un panel de negociación en tiempo real o una interfaz de vídeo—, las peticiones de red adicionales y el tiempo extra de análisis de JavaScript pueden hacer que la aplicación supere su presupuesto.
- Tu equipo tiene menos de cuatro personas en frontend.
- La aplicación tiene menos de cinco fronteras de dominio bien diferenciadas.
- El equipo no tiene experiencia con microservicios ni sistemas distribuidos.
- La organización carece de integración continua y monitorización automatizadas.
- La aplicación tiene presupuestos de rendimiento estrictos que ya cuesta cumplir.
- Las funcionalidades están muy acopladas y no se pueden separar con limpieza en dominios.
Los micro frontends son una decisión organizativa que se manifiesta como arquitectura técnica. Si no necesitas la independencia organizativa que aportan —equipos distintos, ritmos distintos, tecnologías distintas—, el sobrecoste técnico no compensa.
Conclusión
Los micro frontends son un patrón potente para organizaciones que necesitan escalar el desarrollo del frontend entre varios equipos. La arquitectura aporta ventajas reales: despliegue independiente, autonomía de los equipos, libertad tecnológica y la posibilidad de publicar a ritmos distintos. Esas ventajas son ciertas y medibles cuando la arquitectura se aplica al problema adecuado.
La clave del éxito es tratarlos primero como solución organizativa y después como solución técnica. La arquitectura existe para habilitar la independencia de los equipos, no para producir código elegantemente desacoplado. Cada decisión técnica —Module Federation o iframes, monorepo o varios repositorios, bus de eventos o almacén compartido— debería tomarse buscando maximizar la velocidad de los equipos sin perder una experiencia coherente.
Empieza en pequeño. Comienza con un único micro frontend que tenga una frontera de dominio clara y un equipo motivado para llevarlo por su cuenta. Demuestra que la canalización funciona, que el rendimiento es aceptable y que el equipo entrega más rápido. Después amplía poco a poco. Esto no es todo o nada: un enfoque híbrido —uno o dos micro frontends dentro de una aplicación por lo demás monolítica— suele ser el mejor punto de partida.
El fallo más común al adoptarlos es la abstracción prematura. Los equipos construyen elaboradas capas de orquestación, sistemas de estado compartido e infraestructura transversal antes de entender sus necesidades reales. Empieza con la integración más simple posible —una cáscara que cargue micro frontends mediante una etiqueta de script o Module Federation— y añade complejidad solo cuando lo simple se demuestre insuficiente. El nivel adecuado de abstracción se revela con el uso real, no en el diseño previo.
Module Federation ha hecho los micro frontends más accesibles que nunca, pero las preguntas de fondo siguen siendo organizativas. ¿Tus equipos necesitan desplegar de forma independiente? ¿Puede tu organización con la complejidad operativa? ¿Se pueden separar tus dominios con limpieza? Quienes respondan que sí encontrarán en ellos una transformación. Quienes respondan que no, una fuente de frustración. La arquitectura en sí es neutral: su valor depende por completo del contexto en que se aplique.