Micro-frontends existem porque monolitos frontend ficam lentos para desenvolver quando múltiplos times trabalham no mesmo código. Mas a solução introduz complexidade própria, e a maioria dos times que adota micro-frontends subestima essa complexidade.
O problema que micro-frontends resolvem
Em times grandes, 5+ squads trabalhando no mesmo repositório frontend enfrentam: conflitos de merge constantes, builds que ficam mais lentos a cada sprint, difficulty de deploy independente por squad, e acoplamento entre features que deveriam ser independentes.
Micro-frontends separam a aplicação em unidades independentes que são compostas na runtime. Cada squad controla sua parte, faz deploy independente, e não bloqueia os outros.
Abordagens que existem
Build-time integration (Module Federation)
Webpack Module Federation permite que aplicações carreguem módulos de outras aplicações em runtime. Cada micro-frontend é uma aplicação standalone que exporta componentes.
// webpack.config.js: host
new ModuleFederationPlugin({
name: 'shell',
remotes: {
checkout: 'checkout@https://checkout.example.com/remoteEntry.js',
catalog: 'catalog@https://catalog.example.com/remoteEntry.js',
},
})
Run-time integration (iframe ou Web Components)
iframes são a abordagem mais isolada. Web Components permitem composição mais granular, mas exigem uma camada de comunicação entre micro-frontends.
Server-side composition (SSI, ESI, edge-side includes)
O servidor compõe micro-frontends antes de enviar ao cliente. Elimina waterfalls de carregamento mas requer infraestrutura de servidor que suporte includes.
O que muda na prática
// Estrutura típica
shell-app/ # Shell que monta a página
├── src/
│ ├── Header.tsx # Compartilhado entre todos
│ ├── Footer.tsx # Compartilhado entre todos
│ └── MicroApp.tsx # Loader de micro-frontends
│
checkout/ # Squad de checkout
├── src/
│ ├── Checkout.tsx
│ ├── Payment.tsx
│ └── Shipping.tsx
│
catalog/ # Squad de catálogo
├── src/
│ ├── ProductList.tsx
│ └── ProductDetail.tsx
Os custos que ninguém avisa
- Comunicação entre micro-frontends: dados compartilhados exigem um mecanismo explícito, event bus, store compartilhada, ou prop drilling via shell.
- Estilo consistente: design system compartilhado é obrigatório, não opcional. Cada squad pode customizar, mas a base vem de um pacote comum.
- Performance: múltiplos bundles significam mais requests HTTP, mais JavaScript parseado, mais memória. O shell precisa otimizar carregamento.
- Debug: um bug que cruza fronteiras entre micro-frontends é mais difícil de rastrear do que num monolito.
- Deploy orchestrado: dependências entre micro-frontends podem exigir deploy coordenado, o que elimina parte da independência.
Quando vale a pena
Micro-frontends se justificam quando: você tem 3+ times trabalhando no mesmo frontend, com releases independentes e pouca sobreposição de código. O ganho de velocity do time supera o custo de infraestrutura.
Quando não vale a pena
Se você tem 1-2 times, ou os squads trabalham em features que se sobrepõem constantemente, monolito com boa organização de pastas e módulos é mais simples e mais eficiente. Não adote arquitetura por antecipar problemas que você não tem.
Curtiu o conteúdo?
Construo produtos web e soluções com IA do jeito certo — arquitetura sólida, código sustentável e entrega real.
Vamos conversar