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.

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.

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.

ArchitectureDeployment unitBest fitMain cost
Frontend monolithOne application and releaseOne team or tightly coordinated teamsRelease contention as ownership grows
Modular monolithOne release with enforced domain modulesSeveral teams that can share a release trainBoundaries depend on repository discipline
Micro frontendsIndependent domain applicationsAutonomous teams blocked by shared deploymentsRuntime integration, duplicate code, and operational overhead
Separate sitesIndependent products or subdomainsExperiences that do not require one continuous UINavigation, 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.

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.

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  1. Monolith Decomposition Strategy

    PropertyGuru

    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.

  2. Runtime Code Sharing with Module Federation

    PropertyGuru

    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.

  3. Cross-Team Payment Service

    PropertyGuru

    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.

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.

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.

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.

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.

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.

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.

ReactWebpackModule FederationNestJSTypeScriptNode.jsStorybook

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 Counts

When 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 Data

The 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 Stories

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.

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 →