- Home
- Micro Frontends in React
Micro Frontends in React
Production Architecture with Module Federation
By Oleksii Vasylenko, Technical Lead · Updated
Micro frontends in React are worth the operational cost only when independent teams genuinely need independent releases. The pattern—also searched as microfrontends or micro-frontends—splits one product interface into separately owned applications that users still experience as one site. The code split is easy. Preserving coherent navigation, performance, contracts, and accountability is the actual architecture work.
In This Article
- Why it matters
- Monolith vs Modular Monolith vs Micro Frontends
- React Micro Frontend Architecture: The Production Request Path
- Production evidence
- What Are Microfrontends?
- When Micro Frontends Are the Wrong Choice
- Module Federation without Dependency Chaos
- Routing, State, and Communication between React Applications
- Deployment, Testing, and Observability
- A Production Migration for Four Product Teams
- Frequently asked questions
What This Means for Your Business
Micro frontend architecture applies independent ownership to the browser. A shell supplies the page frame and cross-cutting services; domain applications own vertical slices such as search, checkout, billing, or analytics. Each slice should have its own release decision and failure boundary. If every release still needs a shared integration meeting, the organization has distributed the code without distributing authority.
The biggest mistake is sharing too much. Webpack Module Federation can share React, design-system packages, state libraries, utilities, and feature components at runtime. Every shared item is also a version contract and a possible coordination point. Share the smallest stable foundation. Domain behavior belongs with the team accountable for that domain.
Monolith vs Modular Monolith vs Micro Frontends
Micro frontends are not the default destination for a growing React application. Choose the least distributed design that gives teams the release independence they actually need.
| Architecture | Deployment unit | Best fit | Main cost |
|---|---|---|---|
| Frontend monolith | One application and release | One team or tightly coordinated teams | Release contention as ownership grows |
| Modular monolith | One release with enforced domain modules | Several teams that can share a release train | Boundaries depend on repository discipline |
| Micro frontends | Independent domain applications | Autonomous teams blocked by shared deployments | Runtime integration, duplicate code, and operational overhead |
| Separate sites | Independent products or subdomains | Experiences that do not require one continuous UI | Navigation, identity, and brand continuity |
Start with a modular monolith unless independent deployment is a measured business requirement. Runtime composition is an organizational tool, not a badge of technical maturity.
React Micro Frontend Architecture: The Production Request Path
A useful reference design gives each layer one job. The browser should not need to understand the organization's reporting chart, and one unavailable remote should not erase the entire page.
Route through a stable shell
The shell owns top-level routing, navigation, authentication context, error boundaries, feature flags, and page-level telemetry. It should contain little domain behavior.
Resolve a versioned remote
A manifest maps a domain and environment to a tested remote entry. Pin or control rollout versions so a deployment can be promoted, observed, and rolled back without rebuilding the shell.
Load the domain application
Module Federation or another composition mechanism loads the route-level React module. Loading, timeout, and failure states are product states and need deliberate UI.
Pass a narrow contract
Give the remote stable capabilities such as identity, locale, navigation, and analytics. Do not pass a mutable global store containing the entire product.
Call a domain-owned API
The frontend boundary works best when it follows backend ownership. A checkout team that owns only React components but depends on another team's release for every API change is not autonomous.
Observe and isolate failure
Tag errors, web vitals, logs, and releases by shell and remote version. Error boundaries and kill switches should disable one domain slice without taking down unrelated routes.
The architecture succeeds when ownership follows a user capability from route to data—not when the bundle diagram contains many boxes.
How I Have Used This in Production
Monolith Decomposition Strategy
Led monolith-to-micro-frontend migration for 4 product teams. The critical decision was boundary placement — we split by business domain (listings, payments, analytics, agent tools) rather than by UI layer, so each team owns a vertical slice from route to API call.
Runtime Code Sharing with Module Federation
Implemented Webpack Module Federation for runtime code sharing between independently deployed applications. Kept shared components to the minimum viable set — design tokens, authentication wrapper, and navigation shell — to avoid re-creating monolith coupling.
Cross-Team Payment Service
Engineered unified payment service consumed by all 4 product teams. Exposed as a federated module with a strict contract — teams integrate the payment flow without knowing its internals, and the payment team deploys updates without coordinating releases.
What Are Microfrontends?
Microfrontends are independently developed and deployed frontend applications composed into one product experience. The boundary is normally a business domain or route, not a visual atom. Search, account, checkout, and analytics can be sensible domains. Header, button, form field, and modal are usually design-system components, not independent applications. Splitting by UI layer leaves several teams changing one feature and defeats the ownership goal. React does not supply micro frontend architecture by itself; it renders each application. Composition can happen at build time, on the server, through browser routing, through Web Components, or at runtime with Module Federation. AWS describes a parent application that integrates independently delivered child applications; the important word is independently. Separate repositories without separate deployment authority are still a coordinated system. A micro frontend should remain useful, testable, and releasable when neighboring applications change on a different schedule.
The boundary is organizational before it is technical.
When Micro Frontends Are the Wrong Choice
Do not adopt this pattern to fix slow builds, untidy folders, or weak module boundaries. A monorepo, route-level code splitting, dependency rules, and clear ownership can solve those problems with less runtime machinery. A team of six engineers rarely needs six deployable frontends. It needs a codebase people can understand.
The pattern becomes defensible when several durable teams own distinct product domains, deployment coordination delays customer value, different areas need different release cadences, and the organization is prepared to operate multiple artifacts. Measure the present constraint first: time waiting for another team, release frequency, rollback blast radius, and the percentage of changes crossing domain boundaries.
Module Federation without Dependency Chaos
Webpack Module Federation lets one build expose modules and another load them at runtime. In React systems, React and React DOM are commonly configured as singleton shared dependencies because two incompatible runtimes can break hooks and context identity. The host and remote still need an explicit compatibility policy. Automatic version negotiation is not a substitute for contract tests.
Keep the shared surface boring: design tokens, a small component foundation, identity capabilities, navigation, and telemetry adapters. Do not create a giant shared package for domain models, API clients, feature flags, and every utility function. Shared code changes at the speed of its slowest consumer. Duplication is sometimes cheaper than permanent coordination.
Routing, State, and Communication between React Applications
The shell should own top-level URLs; a remote can own routing beneath its mounted prefix. Define who handles redirects, unknown routes, browser history, and deep links before teams ship independently. URL state is often the cleanest cross-application contract because it survives refresh, supports links, and does not couple React component trees.
For communication, prefer browser events or small typed capability interfaces for facts such as CartUpdated or PaymentCompleted. Use APIs as the source of durable domain state. A shared Redux store looks convenient, but it lets any remote read or mutate another team's internals and ties deployments to one state shape. Global state should be limited to concerns that are truly global: authenticated identity, locale, consent, and perhaps a small navigation contract.
Deployment, Testing, and Observability
Independent deployment needs more than separate pipelines. Every remote should publish a versioned artifact, compatibility metadata, source maps, release markers, and a rollback target. Test contracts between shell capabilities and remote expectations. Run a small integration suite against the deployed composition, then let each domain team own deeper tests inside its boundary.
Monitor real-user performance and errors by remote version. Track load failures, remote-entry latency, JavaScript bytes, duplicate dependencies, React render errors, Core Web Vitals, and failed API calls. A shell-level dashboard without remote tags tells operators that the site is broken but not who can fix it. Add kill switches for optional remotes and a stable fallback for critical routes.
A Production Migration for Four Product Teams
At PropertyGuru, I led a monolith-to-micro-frontend migration for four product teams. We divided ownership by business domain—listings, payments, analytics, and agent tools—rather than by UI layer. The result was not four arbitrary React bundles. Each team received a vertical slice it could change and deploy with fewer cross-team release dependencies.
Webpack Module Federation provided runtime composition, but restraint mattered more than the tool. We kept shared code to design tokens, authentication, navigation, and strict service contracts. A unified payment capability was exposed behind a stable interface so consumer teams did not need its internal implementation. That is the test I now use: if a boundary does not reduce the number of people required to release a change, it is in the wrong place.
Technologies
Supporting Engineering Guides
A decision framework for team autonomy, release contention, runtime cost, failure isolation, platform ownership, and reversible migration.
Related Expertise
Micro frontends are the organizational pattern. The React architecture inside each micro frontend still needs to scale. Here is how I structure those internals.
Frontend Architecture for Financial Systems — When Every Frame and Every Millisecond CountsWhen micro frontends share real-time data — like a payment status updating across teams — the WebSocket architecture must span application boundaries.
Real-Time Systems — WebSockets, Message Queues, and Live DataThe analytics micro frontend at PropertyGuru needed custom D3 dashboards. See how I built executive decision tools inside a federated architecture.
D3.js and Data Visualization — Making Data Tell StoriesFrequently Asked Questions
What are micro frontends and what problem do they actually solve?
Micro frontends solve an organizational problem, not a technical one: they split a frontend monolith so independent teams can deploy without blocking each other. The real value is independent deployability — clear ownership boundaries where each team ships their slice without asking permission. The question is never whether to split the frontend but where to draw the boundaries, and the biggest lesson from production migrations is that sharing too much is worse than sharing too little.
When should a team adopt micro frontends, and when should they not?
Adopt micro frontends when the release cycle is measured in weeks because teams are blocked on a shared monolith — that is the organizational problem the pattern fixes. At PropertyGuru, four product teams were blocked this way before Oleksii led the migration. Teams should not adopt the pattern just because Module Federation makes sharing easy: every shared dependency becomes a coordination point, and without clear ownership boundaries you recreate monolith coupling with more infrastructure on top.
What production micro frontend experience does Oleksii Vasylenko have?
Oleksii led the monolith-to-micro-frontend migration at PropertyGuru, unblocking four product teams. The critical decision was boundary placement: splitting by business domain — listings, payments, analytics, agent tools — rather than by UI layer, so each team owns a vertical slice from route to API call. He implemented Webpack Module Federation for runtime code sharing and engineered a unified payment service exposed as a federated module with a strict contract, consumed by all four teams.
What is the biggest mistake teams make with micro frontends?
Sharing too much. Webpack Module Federation makes it easy to share components across applications, but every shared dependency becomes a coordination point — if Team A updates a shared component and Team B has not tested against it, you have recreated the monolith coupling with more infrastructure. At PropertyGuru, Oleksii kept shared components to the minimum viable set: design tokens, an authentication wrapper, and the navigation shell. Everything else stayed inside team-owned vertical slices.
How can a team blocked on a shared frontend engage Oleksii Vasylenko?
Oleksii has led this migration for a platform with four product teams and can tell you exactly where to draw the boundaries. At PropertyGuru he split the monolith by business domain, kept Module Federation sharing to a minimum viable set, and delivered a cross-team payment service teams integrate without coordinating releases. If your release cycle is measured in weeks because of frontend coupling, contact him through ovasylenko.com to discuss the migration strategy.
How do micro frontends work with React?
A shell renders top-level navigation and routes, then loads domain-owned React applications through Module Federation, import maps, server composition, or another integration method. React is the rendering library, not the architecture. Teams still need contracts for routing, identity, shared dependencies, failure states, telemetry, and independent deployment.
Should React micro frontends share state?
Share as little mutable state as possible. Identity, locale, consent, and navigation may belong at shell level. Durable domain state should remain behind domain APIs, while cross-application facts can travel through typed events or narrow capability interfaces. One shared Redux store couples every remote to one release-sensitive state model.
Further Reading
Teams blocked on a shared frontend?
The monolith is not the problem — the coupling is. I have led this migration for a platform with 4 product teams and can tell you exactly where to draw the boundaries. If your release cycle is measured in weeks, it does not have to be.
Discuss your frontend architectureEngagement options and availability →