Micro-Frontend Architecture: Lessons from 20+ Product Initiatives
Practical lessons learned from implementing and working with microfrontend architectures across multiple teams and product initiatives.
Pietro Dessotti
Senior Frontend Engineer at Zenvia
After contributing to over 20 product initiatives across multiple engineering teams, I've accumulated strong opinions about when microfrontends help and when they add unnecessary complexity. Here's what I've learned.
What Microfrontends Actually Solve
Microfrontends don't solve a technical problem. They solve an organizational one. The core value proposition is team autonomy: the ability for multiple teams to own, deploy, and evolve their own UI surfaces without coordinating with every other team on every release.
If you have one team, you don't need microfrontends. If you have ten teams shipping to the same frontend codebase, you almost certainly do.
The Deployment Boundary is the Real Benefit
Most people focus on technology when discussing microfrontends: module federation, single-spa, and iframes. But the technology is secondary. The critical thing is the deployment boundary.
Each team controls their own deployment pipeline. A bug in Team A's checkout flow doesn't block Team B from shipping new features. This alone can dramatically change how teams operate.
// Module Federation host configuration
// apps/shell/webpack.config.js
new ModuleFederationPlugin({
name: 'shell',
remotes: {
checkout: 'checkout@https://checkout.example.com/remoteEntry.js',
catalog: 'catalog@https://catalog.example.com/remoteEntry.js',
},
shared: {
react: { singleton: true, requiredVersion: '^18.0.0' },
'react-dom': { singleton: true, requiredVersion: '^18.0.0' },
},
})
The Design System Problem
One of the first challenges you'll face: each microfrontend may end up with a slightly different version of your component library. Team A upgrades the button. Team B doesn't. Now your users see two different button styles on the same page.
The solution isn't forcing everyone to update at the same time. It's designing your shared packages to be stable and versioning them carefully. Treat your design system like a public API.
When It Goes Wrong
I've seen microfrontends fail in two main ways:
1. Premature decomposition. Teams split the frontend before they had clear team ownership boundaries. The result is 12 microfrontends maintained by 3 people. Complexity without benefit.
2. Shared state hell. Teams try to share too much state across boundaries, such as user sessions, shopping carts, and UI preferences. Each new shared concern erodes the autonomy you were trying to achieve.
The rule of thumb: if two microfrontends need to communicate frequently, they may belong in the same application.
What I'd Do Differently
Starting fresh today, I'd:
- Start with a monorepo, not microfrontends. Extract only when team growth demands it.
- Define ownership boundaries before technical boundaries. Conway's Law applies.
- Invest heavily in the design system first. It's the foundation everything else sits on.
- Keep the shell application thin. Limit it to routing and authentication.
Microfrontends are a powerful tool. But like any powerful tool, they require understanding the problem before reaching for the solution.