Micro-frontends are a web architecture style in which a single user-facing application is split into independently developed, tested and deployed frontend parts, each owned by one team and usually aligned with a business domain such as search, checkout or account management. The parts are then composed into one coherent interface in the browser, on the server or at the edge.
The idea, also written as microfrontends, extends the principles of microservices to the frontend. Its main goal is organizational scalability: letting many teams ship their parts of a large product without coordinating every release, at the price of added runtime and governance complexity.
How micro-frontends are structured
A micro-frontend system has two kinds of components: domain applications that render features, and a shell or container application that loads them, provides routing and shared layout, and passes context such as the signed-in user. Each domain application has its own repository or package, build pipeline and release schedule.
Boundaries are drawn vertically by business capability, not horizontally by technical layer. A checkout team owns the checkout pages, their components, their backend for frontend and often their data APIs. This vertical slicing lets a team deliver a feature end to end without waiting for a shared frontend team.
Communication between parts is deliberately narrow and explicit: URL parameters, custom DOM events, a small publish and subscribe bus or attributes on custom elements. Sharing global state or reaching into another team’s internal components recreates the coupling the architecture is meant to remove.
Ownership also extends to operations. Each team runs its own continuous integration pipeline, feature flags and monitoring, and a release of one micro-frontend must never require a simultaneous release of another. When two parts must change together, it is a signal that the boundary between them is drawn in the wrong place.
Integration techniques for composing micro-frontends
Composition can happen at build time, on the server, at the edge or in the browser. The choice determines how independent deployments really are and how fast the first view appears.
| Technique | Where composition happens | Independent deployment | Main trade-off |
|---|---|---|---|
| Build-time packages | Build of the shell | No, shell must rebuild | Simple but tightly coupled releases |
| Server-side includes | Web server or edge | Yes | Fast first view, limited interactivity glue |
| Runtime JavaScript loading | Browser | Yes | Flexible, larger bundles possible |
| Module Federation | Browser, via bundler runtime | Yes | Shared dependencies, version negotiation |
| Web components | Browser | Yes | Framework-neutral, styling isolation needed |
| Iframes | Browser | Yes | Strong isolation, poor integration and performance |
Server-side and edge composition suits content-heavy pages where first paint matters, while runtime composition suits application-like products. Many large systems combine them: the server assembles the page skeleton and fragments, and the browser activates each fragment’s interactive code.
Micro-frontends compared with other frontend architectures
Micro-frontends sit between a single frontend monolith and fully separate applications. A well-structured monolith is usually the better starting point for small organizations.
| Architecture | Team autonomy | Runtime complexity | Typical fit |
|---|---|---|---|
| Frontend monolith | Low to medium | Low | One or a few teams |
| Modular monorepo | Medium | Low | Several teams, shared release |
| Micro-frontends | High | Medium to high | Many teams, separate releases |
| Separate applications per domain | Very high | Low per app | Loosely related products |
The pattern pairs naturally with backend for frontend services and with headless architecture, because each team can own the API layer that serves its interface. It is unrelated to component libraries, which share UI building blocks but do not split deployment ownership.
Micro-frontends also differ from simple code splitting. Code splitting divides one build into lazily loaded chunks, but all chunks still come from one codebase and one deployment. Micro-frontends divide the build and the deployment themselves, so two parts of the same page may reach production on different days and even use different framework versions, which is both their strength and their main risk.
When micro-frontends are worth adopting
Micro-frontends solve a people and delivery problem, not a technical performance problem. They pay off when coordination cost between teams exceeds the cost of running a distributed frontend.
| Situation | Recommendation | Reason |
|---|---|---|
| Fewer than about three frontend teams | Stay with a modular monolith | Overhead outweighs autonomy gains |
| Many teams blocked by shared releases | Adopt micro-frontends by domain | Independent deployment removes queues |
| Gradual migration from a legacy framework | Use micro-frontends as a strangler pattern | Replace one area at a time |
| Product built by acquired companies | Compose existing apps behind one shell | Unified experience without rewrites |
| Performance-critical landing pages | Prefer server composition or avoid | Runtime loading adds weight |
Successful adoptions invest early in a shared design system, a lightweight shell, contract tests for integration points and observability across fragments, so that a fault can be traced to the owning team quickly.
Risks and common mistakes
- Duplicate dependencies: several teams shipping different framework versions can multiply JavaScript weight and slow every page.
- Inconsistent user experience appears when teams diverge on styles, wording and interaction patterns without a design system.
- Shared state coupling through global stores turns independent parts into a distributed monolith.
- Boundaries drawn too small, such as one micro-frontend per widget, create integration overhead with no autonomy benefit.
- CSS leakage between parts causes visual bugs unless styles are scoped, prefixed or encapsulated in shadow DOM.
Teams should define performance budgets per fragment and a policy for shared libraries. Without such governance, the architecture tends to deliver organizational speed at the expense of users, which is rarely an acceptable trade.
The short version
Think of a large department store. Each department, such as shoes, electronics or groceries, has its own staff who arrange and restock it whenever they want, while the building, entrances and signs are shared so customers experience one store.
Micro-frontends organize a big website the same way. Separate teams build and update separate sections of the site independently, and a common frame stitches them together. The benefit is that teams do not wait for each other. The cost is that someone must keep the whole store consistent and prevent each department from slowing down the building.
Where it makes a difference
A large online retailer has eight frontend teams working in one single-page application. Every release requires a shared regression cycle, and a bug in the reviews area can block a fix in checkout for days. Release frequency has dropped to once every two weeks.
The company introduces a thin shell with routing and authentication and splits the product into domains: search, product details, cart and checkout, and customer account. Product pages are composed at the edge for fast first paint, while account and checkout load as runtime modules sharing one framework version. A common design system keeps the interface uniform. Within a few months, each team deploys several times a week, and a performance budget per fragment keeps total JavaScript within its previous size.