- Los microfrontends extienden la idea de los microservicios al frontend, dividiendo una gran aplicación en módulos autónomos alineados con dominios de negocio.
- Permiten que equipos verticales trabajen de forma independiente con despliegues desacoplados, mejorando escalabilidad, autonomía y frecuencia de entrega.
- Añaden complejidad arquitectónica y operativa, por lo que solo resultan rentables en aplicaciones grandes con muchos equipos y alta demanda de cambios.
- Su implementación se apoya en técnicas como Module Federation, Web Components, SSR y buenas prácticas de diseño, rendimiento y experiencia de usuario.
Si trabajas en desarrollo web y tu aplicación no para de crecer, es muy probable que el frontend se te haya convertido en un monstruo difícil de mantener: builds eternos, equipos pisándose el código y cualquier cambio pequeño con riesgo de romper media web. En este contexto aparecen los microfrontends como una arquitectura pensada para trocear esa interfaz gigante en piezas más manejables que pueden evolucionar de forma independiente.
A lo largo de las últimas décadas hemos pasado de páginas HTML casi estáticas a aplicaciones web ricas y complejas que compiten con el software de escritorio. Esa evolución ha traído muchas ventajas… y también nuevos problemas de escalabilidad, organización de equipos y rendimiento. En este artículo vamos a ver con detalle cómo funcionan los microfrontends, por qué surgieron, cuándo merece la pena aplicarlos y qué tecnologías se usan para ponerlos en marcha, apoyándonos en ejemplos prácticos y en las buenas prácticas que se han ido consolidando en la industria.
Qué son los microfrontends y de dónde vienen
El término microfrontends aparece por primera vez en 2016 en el ThoughtWorks Technology Radar, el mismo ecosistema que popularizó los microservicios. La idea es sencilla de entender: si hemos aprendido a dividir el backend en microservicios independientes para ganar escalabilidad y flexibilidad, ¿por qué no aplicar una filosofía similar en la capa de interfaz de usuario?
En una arquitectura clásica, el frontend suele ser una aplicación monolítica, normalmente una SPA enorme construida en React, Angular, Vue u otra tecnología. Con el tiempo esa SPA va acumulando lógica, rutas, componentes, estilos, estados globales… hasta el punto de que resulta muy costoso evolucionarla sin romper cosas. A eso se le suele llamar “frontend monolítico”.
Los microfrontends proponen ver la aplicación web como un conjunto de funcionalidades o dominios de negocio separados (por ejemplo: catálogo, checkout, perfil, reporting) donde cada dominio se implementa como una aplicación frontend autónoma, mantenida por un equipo distinto, y que después se integran visualmente en una experiencia única para el usuario.
Martin Fowler lo describe como “un estilo arquitectónico en el que múltiples frontends independientes se combinan en un todo mayor”. Es un enfoque muy parecido a conceptos anteriores como los “sistemas autocontenidos” o los “sistemas verticales”, pero con un nombre más amigable y alineado con el mundo moderno de la web.
En la práctica, esto significa que cada equipo es cross-functional y se responsabiliza end-to-end de su parte: desde la base de datos y el backend (microservicio) hasta el microfrontend y la experiencia de usuario, evitando depender continuamente de otros equipos para entregar valor.
Evolución de las arquitecturas web: del monolito a los microfrontends
Para entender bien por qué los microfrontends tienen sentido, conviene repasar cómo hemos llegado hasta aquí: la web empezó con documentos estáticos enlazados entre sí, orientados al contenido, mientras que las aplicaciones de escritorio ya tenían arquitecturas maduras (MVC, capas, patrones de diseño) pensadas para software complejo.
Con la aparición de JavaScript y la mejora de los navegadores, empezamos a dotar de interactividad a esas páginas. Luego llegaron los frameworks frontend modernos y el concepto de Single Page Application, que concentra gran parte de la lógica en el navegador para ofrecer experiencias muy ricas y rápidas.
En el backend ocurrió algo parecido: inicialmente el servidor solo generaba HTML a partir de datos, pero las necesidades crecientes empujaron a adoptar arquitecturas más sofisticadas y finalmente microservicios, donde cada servicio cubre una parte de la funcionalidad de negocio y puede desplegarse de forma aislada.
La paradoja es que mientras el backend se troceaba en microservicios, el frontend seguía siendo un único bloque enorme que consumía esos servicios. De ahí surge la idea: si el backend ya está dividido, tiene sentido reflejar una división similar en la interfaz, alineando equipos por verticales de negocio en lugar de por capas técnicas.
Podemos visualizar esta evolución como una progresión: monolito compacto sin capas claras → monolito organizado con MVC → backend de microservicios + frontend monolítico → backend de microservicios + frontend dividido en microfrontends, donde cada vertical cubre todo el stack.
Ideas clave y principios de diseño en microfrontends
Más allá del concepto general, la comunidad que ha trabajado con microfrontends ha ido refinando una serie de principios que ayudan a que esta arquitectura funcione bien en la práctica y no derive en caos:
- Agnosticismo tecnológico razonable: cada equipo debería poder elegir su stack (React, Angular, Vue, Svelte, Web Components…) sin bloquear a los demás, aunque conviene limitar la diversidad para evitar una “anarquía de frameworks”.
- Aislamiento de código y runtime: se recomienda no compartir tiempo de ejecución ni estados globales si no es imprescindible. Cada microfrontend debería ser autónomo y no depender de variables globales ni singletons compartidos.
- Prefijos y espacios de nombres por equipo: usar convenciones de nombres (por ejemplo, prefijos de CSS, nombres de eventos, claves de almacenamiento local o cookies) para evitar colisiones y dejar clara la propiedad de cada pieza.
- Apostar por APIs del navegador antes que inventar infraestructuras propias: para la comunicación, es preferible usar eventos del DOM y Custom Events en vez de diseñar buses globales complejos o PubSub caseros.
- Construir interfaces resilientes: la funcionalidad debe aportar valor incluso si JavaScript falla o tarda en cargarse. Se suelen combinar técnicas como renderizado universal (SSR) y mejora progresiva.
Si aplicamos estos principios con cabeza, podemos tener múltiples equipos trabajando en paralelo sin romperse los unos a los otros, manteniendo al mismo tiempo una experiencia unificada para el usuario final.
Cómo se componen los microfrontends: el DOM como API y los Custom Elements
Uno de los enfoques más potentes para integrar microfrontends en el navegador es usar Web Components y, en concreto, Custom Elements. La idea es que cada equipo empaquete su funcionalidad dentro de una etiqueta personalizada del estilo <blue-buy sku="t_porsche"></blue-buy>.
En este modelo, el DOM actúa como contrato público entre equipos. La “API” de ese componente no es una clase o una interfaz TypeScript, sino la propia especificación de su etiqueta: nombre del elemento, atributos soportados y eventos que emite. Cualquier otro equipo puede usar el componente sin conocer su implementación interna, siempre que respete ese contrato.
Cuando el navegador encuentra un Custom Element, ejecuta el método connectedCallback() de la clase que lo define, pasando a partir de ahí a comportarse como un elemento estándar con sus propiedades, métodos y eventos. También podemos implementar attributeChangedCallback() para reaccionar a cambios en atributos específicos.
La convención más habitual es que el nombre del Custom Element incluya un guion para garantizar la compatibilidad con especificaciones HTML futuras, por ejemplo <order-minicart> o <blue-buy>. Además, se acostumbra a usar el prefijo del equipo como parte del nombre para evitar colisiones y dejar clara la responsabilidad mirando el DOM.
Hoy en día, todos los grandes frameworks frontend soportan Web Components: puedes incrustar un Custom Element en React, Angular, Vue, Svelte o Preact como si fuera una etiqueta HTML más, y muchos permiten empaquetar tu aplicación como un Web Component reutilizable.
Integración cliente-servidor y renderizado en servidor (SSR)
Renderizar los microfrontends solo en el cliente puede provocar pantallas en blanco mientras llega el JavaScript, algo desastroso para la percepción de rendimiento y para la resiliencia si algo falla al cargar los bundles. Por eso, muchas implementaciones combinan Custom Elements en el navegador con técnicas de SSR en el servidor.
Un patrón muy interesante consiste en que cada equipo exponga en su servidor un endpoint que devuelve el HTML de su fragmento (lo que internamente podría ser el resultado de su método render()). Luego, el servidor web principal (por ejemplo Nginx) monta la página usando Server Side Includes (SSI) o variantes como ESI, donde cada fragmento HTML se inserta en la respuesta antes de enviarla al navegador.
Así se consigue algo parecido a un “componente web universal”: el mismo fragmento se puede renderizar en el servidor vía SSI y, una vez cargado el JavaScript en cliente, rehidratar o mejorar progresivamente ese contenido sin que el usuario note un cambio brusco.
El inconveniente de este enfoque es que el tiempo de respuesta de la página queda condicionado por el microfrontend más lento. Por eso se suele recurrir a cachear fragmentos costosos y, en algunos casos, a no incluir ciertos bloques en el SSR inicial, cargándolos asíncronamente en el navegador cuando sea razonable.
Un ejemplo típico es una sección de recomendaciones personalizadas: podemos servir inicialmente un espacio vacío o, mejor aún, un skeleton simple que reserve espacio y evitar reflows molestos, y después rellenarlo con el contenido definitivo cuando el microfrontend correspondiente haya obtenido los datos.
Comunicación entre microfrontends y gestión del estado
En una arquitectura con muchos microfrontends, uno de los puntos críticos es decidir cómo se comunican entre sí y cómo gestionan el estado compartido, si es que lo hay. Aquí suelen entrar varias estrategias complementarias:
- Atributos y propiedades del DOM: para relaciones padre-hijo, muchas veces basta con actualizar atributos de un Custom Element (por ejemplo,
skuen un botón “comprar”). El elemento reacciona a estos cambios y se vuelve a renderizar. - Eventos del DOM (CustomEvent): para notificaciones más desacopladas (por ejemplo, “se ha añadido un producto al carrito”), se crean eventos personalizados que hacen bubbling por el árbol del DOM y que pueden ser capturados por cualquier componente interesado.
- APIs globales muy bien encapsuladas: en algunos casos puede tener sentido exponer métodos imperativos en elementos DOM (como
refresh()en una minicesta) o un pequeño SDK compartido, siempre que no vulnere el aislamiento. - Gestión de estado por microfrontend: cada microfrontend suele tener su propio store (Redux, NgRx, Zustand, MobX, etc.) para su estado interno, evitando un gran estado global que obligue a coordinar equipos continuamente.
Conviene evitar, en la medida de lo posible, estados globales masivos o librerías compartidas de gestión de estado que acoplen demasiado los microfrontends. Si necesitas que dos o más módulos intercambien datos constantemente, es probable que en realidad formen parte del mismo dominio y deban ser un único microfrontend en lugar de varios.
Organización de equipos: verticales y dominios de negocio
Una de las grandes ventajas de los microfrontends no es solo técnica, sino organizativa: permite estructurar los equipos por funcionalidad de negocio y no por capas técnicas. Este patrón se suele llamar “organización vertical”.
Imagina una tienda online de zapatillas. En lugar de tener un “equipo de frontend”, otro de “backend” y otro de “bases de datos”, podrías montar equipos orientados a áreas como búsqueda y filtros, listado de productos, carrito y checkout, cuenta de usuario, etc.
Cada equipo se ocupa de su microfrontend (o microfrontends) y de los servicios backend asociados. Eso les permite tomar decisiones rápidas, desplegar con independencia y responsabilizarse de principio a fin de los resultados, sin depender día sí y día sí de otros grupos.
En la prueba de concepto típica, la homepage de la tienda podría contener:
- Un microfrontend para la búsqueda y filtrado de zapatillas.
- Otro microfrontend para el listado de resultados.
- Un tercero para el carrito de compra.
- Y un microfrontend contenedor (host) que orquesta e integra visualmente los anteriores.
De cara al usuario todo se ve como una sola página. Pero, internamente, cada bloque tiene su repositorio, su pipeline de CI/CD y su ciclo de releases, lo que reduce fricciones y favorece entregas frecuentes y bien acotadas.
Ventajas de la arquitectura de microfrontends
Aplicar microfrontends en proyectos grandes puede aportar un montón de beneficios, siempre que se haga con cabeza. Algunos de los más importantes son:
- Equipos autónomos y despliegues independientes: cada microfrontend puede ser desarrollado, testeado y desplegado sin arrastrar al resto de la aplicación. Si hay un bug en el carrito, se corrige y se despliega solo esa pieza.
- Mejor escalabilidad técnica y organizativa: el código se divide en módulos manejables y los equipos crecen por verticales de negocio, distribuyendo mejor la carga de trabajo.
- Menores riesgos en cambios y releases: al estar el código más aislado, los errores tienden a quedar acotados a un dominio concreto y es menos probable tirar abajo todo el sitio con un simple cambio.
- Performance potencialmente mejorada: si se diseña con cuidado, se puede cargar solo lo necesario de cada microfrontend (code splitting, lazy loading), reduciendo el peso inicial de la aplicación.
- Facilidad de pruebas y mantenimiento: probar un microfrontend aislado es más sencillo que testear una SPA gigantesca donde cualquier interacción toca múltiples partes.
- Posibilidad de mezclar tecnologías cuando sea inevitable: aunque no se recomienda abusar, los microfrontends permiten introducir nuevos frameworks o migrar gradualmente desde uno antiguo sin reescribir todo de golpe.
Inconvenientes, riesgos y cuándo NO usar microfrontends
No todo son ventajas. Los microfrontends también tienen su cara B y añaden complejidad arbitraria si se aplican donde no hace falta. Algunos de los principales inconvenientes son:
- Mayor complejidad arquitectónica y operativa: se necesitan más repositorios, más pipelines, más entornos, más coordinación. El coste de infraestructura y de orquestación sube.
- Gestión de estado más complicada: cuando varias partes necesitan compartir información, coordinar el estado global puede ser delicado y requiere un diseño cuidadoso.
- Riesgos de inconsistencia visual y de UX: si cada equipo va por libre, acabas con un frankenstein visual donde cada zona de la app parece de una empresa distinta.
- Incremento del tamaño de los bundles y de las peticiones HTTP: si cada microfrontend arrastra sus propias dependencias, el peso total puede dispararse y empeorar el rendimiento.
- Carga inicial más pesada: dependiendo de la estrategia, cargar múltiples microfrontends puede aumentar el tiempo hasta que el usuario ve algo útil.
- Curva de aprendizaje: los equipos deben aprender nuevas formas de trabajar, herramientas (como Module Federation, single-spa, etc.) y patrones de integración.
Por todo esto, es fundamental no aplicar microfrontends a cualquier proyecto. En aplicaciones pequeñas (un blog, una web corporativa sencilla, un portfolio, pruebas de concepto de bajo alcance) suele ser suficiente con una buena componentización dentro de un único frontend. Reservar los microfrontends para cuando:
- La aplicación es grande o va a crecer mucho y se espera un aumento fuerte de funcionalidad y tráfico.
- Participan muchos desarrolladores repartidos en varios equipos que necesitan trabajar en paralelo sin pisarse continuamente.
- Se requiere desplegar partes de la aplicación con mucha frecuencia, minimizando el riesgo en cada release.
- Se detectan cuellos de botella claros en un frontend monolítico que ya se ha quedado pequeño en términos organizativos.
Tecnologías y enfoques para implementar microfrontends
Hay varias estrategias y herramientas populares para montar una arquitectura de microfrontends. Las más utilizadas hoy por hoy son:
- Module Federation (Webpack 5, Vite, etc.): permite compartir módulos entre aplicaciones independientes en tiempo de ejecución. Es ideal para que un “host” cargue microfrontends remotos escritos incluso con distintos frameworks.
- single-spa y derivados (como qiankun): un framework pensado para combinar múltiples SPAs en una sola app, gestionando el enrutado y el ciclo de vida de cada subaplicación.
- Web Components: basados en estándares como Custom Elements, Shadow DOM y HTML Templates, son perfectos para encapsular componentes reutilizables y aislar estilos y comportamiento.
- SSI / ESI / Tailor / Compoxure: técnicas de composición en servidor de fragmentos HTML generados por distintos servicios, útiles para SSR y para apps muy orientadas a contenido.
- iframes: una solución muy aislada, útil a veces para integrar aplicaciones legadas, pero con limitaciones importantes en UX y comunicación.
- BFF (Backend for Frontend): aunque no es una técnica de microfrontends en sí, suele acompañarlos: cada frontend o microfrontend tiene un backend a medida que le sirve exactamente los datos que necesita.
En el ecosistema JavaScript moderno, Module Federation se ha convertido en uno de los pilares más sólidos. Con Webpack 5 (y también con Vite mediante plugins) se define en cada aplicación:
- Qué módulos se exponen como remotos (por ejemplo, el microfrontend de carrito, el de listado, etc.).
- Qué módulos se consumen desde otros orígenes (por ejemplo, el host que importa esos microfrontends).
- Qué dependencias se comparten (React, Angular, librerías comunes, etc.) para evitar duplicidades.
El resultado es que el host puede importar dinámicamente componentes remotos como si fueran módulos locales, pero en realidad están siendo servidos por otras aplicaciones desplegadas en servidores y puertos diferentes.
Microfrontends con React, Angular y Next.js
En el terreno de los frameworks concretos, hay varios patrones ya bastante maduros para trabajar con microfrontends:
Con React, la combinación de Module Federation y el ecosistema de librerías (router, stores, etc.) hace que sea muy cómodo crear microfrontends independientes. React facilita el rendering eficiente y la migración de versiones también suele ser más sencilla que en otros frameworks, lo que ayuda a que cada microfrontend avance a su ritmo.
El principal reto en React con microfrontends es que, si cada módulo lleva su propia copia de React y dependencias anexas, el peso de descarga puede dispararse y afectar a los tiempos de carga. Por eso es importante configurar bien las dependencias compartidas y usar técnicas de lazy loading.
Con Angular, la propia herramienta y su arquitectura encajan bastante bien: Angular organiza proyectos en espacios de trabajo, proyectos y librerías, lo que se refleja muy bien en un monorepo que contenga varios microfrontends. Desde Angular 12 se integra Module Federation de Webpack 5, y herramientas como Nx facilitan la orquestación.
En este contexto, las librerías compartidas permiten reutilizar componentes y utilidades entre microfrontends sin duplicar código. Se suelen usar también patrones como arquitectura hexagonal dentro de cada microfrontend, junto con NgRx para el manejo de estado, lo que favorece la mantenibilidad a largo plazo.
En el caso de Next.js, el framework de React para producción, la idea es aprovechar su modelo de renderizado híbrido (SSR y SSG) junto con Module Federation para construir microfrontends que se integran en una app Next “host”. Next 10.2 en adelante soporta Webpack 5 de serie, y en versiones anteriores se podía recurrir a paquetes externos para integrarlo.
Este enfoque es muy interesante cuando quieres que cada sección o grupo de páginas de tu sitio Next sea un microfrontend independiente, lo cual permite a equipos diferentes entregar funcionalidades sin afectar al resto del sistema.
Buenas prácticas para trabajar con microfrontends
Para sacarles partido sin morir en el intento, conviene seguir una serie de buenas prácticas que se han ido consolidando en la industria:
- Limitar la diversidad tecnológica: aunque es tentador dejar que cada equipo use el framework que le apetezca, en la práctica compensa alinear el stack principal (por ejemplo, todo en React o todo en Angular) y reservar excepciones para casos muy justificados.
- Evitar sobre-fragmentar la aplicación: hacer microfrontends demasiado pequeños lleva a un exceso de componentes sin valor real y a una complejidad brutal en coordinación. Un buen criterio es que cada microfrontend cubra un propósito de negocio claro y unívoco.
- Definir contratos claros entre equipos: es fundamental acordar cómo se comunican las APIs, qué eventos emite cada módulo, qué atributos soporta cada componente, etc., y documentarlo bien.
- Alinear la arquitectura con la organización: de poco sirve tener microfrontends si luego el negocio exige desplegar todo a la vez. Si la empresa sigue siendo “monolítica” en procesos, la arquitectura no aportará gran cosa.
- Pensar en rendimiento desde el principio: aprovechar el code splitting, el lazy loading y la cache para no penalizar la carga inicial, y usar skeletons para mejorar la percepción del usuario en cargas parciales.
- Cuidar la consistencia visual y de UX: apoyarse en un sistema de diseño compartido o una librería de componentes común (incluso como Web Components neutrales al framework) para evitar que cada microfrontend parezca de un producto diferente.
- No obsesionarse con la reutilización entre microfrontends: intentar que todo sea reutilizable puede acabar complicando los despliegues y aumentando las dependencias entre equipos. La mayoría de microfrontends representan dominios muy específicos que no se van a copiar tal cual en otros sitios.
- Probar a distintos niveles: además de las pruebas unitarias de cada microfrontend, hacen falta tests de integración y end-to-end que validen cómo se comportan juntos en el host.
Cuándo y cómo empezar con microfrontends
Si estás valorando dar el salto, lo más sensato es empezar con una parte concreta y bien acotada de tu aplicación, en lugar de reescribirlo todo de golpe. Por ejemplo, podrías convertir en microfrontend el área de checkout, o el módulo de administración, y comprobar en la práctica si la arquitectura encaja con vuestra forma de trabajar.
A nivel de desarrollo local, suele ser útil estandarizar herramientas: Node y framework en versiones alineadas, un arquetipo o plantilla de proyecto común (por ejemplo, un arquetipo corporativo para apps web con opción MFE), y scripts de arranque coherentes para todos los microfrontends.
En el plano de despliegue, conviene coordinar con los equipos de infraestructura u operaciones para disponer de entornos adecuados donde cada microfrontend tenga su propio pipeline, y donde el host pueda cargar los remotos de forma segura y versionada. En muchas organizaciones esto pasa por integrarse en procesos como DevSecOps y plataformas pre-cloud o cloud.
Dentro de cada microfrontend se pueden aplicar patrones internos como arquitectura hexagonal, componentes standalone, gestión de estado con NgRx, Redux o similares, y pruebas unitarias con frameworks habituales (Jasmine, Karma, Jest…). Todo esto ayuda a que, aunque la aplicación total sea compleja, cada pieza se mantenga limpia y ordenada.
Adicionalmente, los componentes transversales (por ejemplo, cabeceras, barras de navegación o widgets comunes) pueden exponerse como Web Components independientes (incluso construidos con Vue u otro framework) para garantizar la coherencia visual en todos los microfrontends sin atarlos al stack concreto de cada uno.
Los microfrontends ofrecen una manera potente de tamear frontends gigantes dividiéndolos en módulos autónomos alineados con el negocio, pero exigen disciplina, acuerdos entre equipos y una buena base técnica y organizativa; usados con criterio pueden ser una palanca brutal para escalar producto y equipos, pero aplicados por moda o sin una necesidad real se convierten fácilmente en sobreingeniería innecesaria y en un quebradero de cabeza continuo.
