All writing
Published

Architecture

Architecting Micro-Frontends at Scale: Module Federation in Angular vs. React

Field notes on ownership boundaries, deployment discipline, shared dependencies, and the social architecture behind MFEs — comparing Angular and React approaches.

·

11 min read

Micro-frontendsModule FederationArchitecture

Micro-frontends are one of those architectural decisions that sound clean in a diagram and get messy in practice. I've lived through the messy part — migrating a monolithic Ruby on Rails ERB application into a React micro-frontend serving millions of users — and this is the guide I wish I'd had before we started.

Start with the problem, not the pattern

Teams reach for micro-frontends for different reasons: independent deployment, team autonomy, incremental migration from a legacy monolith, or scaling the build itself. The reason matters because it determines your boundaries, your contract strategy, and how much coordination overhead you're willing to accept.

Our reason was migration. We had a large Rails application where the frontend and backend were deeply entangled. We couldn't rewrite it all at once, so we needed a way to extract vertical slices into modern React without a flag-day cutover. Module Federation gave us that on-ramp.

Ownership boundaries

The first hard lesson: boundaries should follow business domains, not technical layers. A 'navigation team' and a 'content team' will create coupling at every page. A 'Commitments team' that owns the full vertical — UI, API, data model — ships independently and resolves incidents without a war room.

  • Draw your boundaries around pages or feature areas, not components.
  • Each micro-frontend should own its route(s) end-to-end, including data fetching.
  • Shared UI is acceptable, but treat it like an open-source dependency: versioned, documented, and consumed through a package — not through direct imports across teams.

Module Federation: the mechanics

Webpack Module Federation lets one build expose modules that another build consumes at runtime. The host (shell) loads remotes on demand, and shared dependencies — React, your design system — are deduplicated so you don't ship two copies of React to the browser.

Angular's take

Angular's ecosystem has mature federation support via the @angular-architects/module-federation package. It integrates with the Angular CLI and NgRx, and the framework's opinionated structure means conventions are enforced more naturally. The trade-off is that you're working within Angular's bootstrapping model, which adds ceremony to the host-remote handshake.

React's take

React is unopinionated, which is both the advantage and the risk. You have full control over the host shell, lazy loading, and boundary error handling — but you also own every convention. In practice, I found React federation faster to prototype but requiring more discipline to keep consistent across teams.

Shared dependencies: where it gets real

Version skew is the silent killer. If your shell runs React 18.2 and a remote was built against 18.0, you may get subtle reconciliation bugs that only surface in production. The defenses are unglamorous but essential:

  • Pin shared singleton versions and enforce them through CI checks.
  • Establish an upgrade cadence — a shared dependency bump is a coordinated event, not a surprise.
  • Keep the shared surface small. Every library you share is a library you've committed to synchronizing.

Deployment discipline

Independent deployment is the payoff, but it requires infrastructure maturity. Each remote needs its own pipeline, its own rollback story, and its own health checks. The shell must be resilient to a remote being unavailable — a failed remote load should degrade gracefully, not blank the page.

A micro-frontend architecture is only as independent as its weakest shared dependency.

The social architecture

The hardest part isn't technical. It's organizational. Micro-frontends work when teams trust each other's contracts, when there's a clear escalation path for cross-team issues, and when someone owns the platform — the build tooling, the shared libraries, the deployment infrastructure — as a first-class concern.

If your organization doesn't have the appetite for that platform investment, a well-structured monolith will outperform a federation that nobody owns. The pattern is a tool, not a destination.


Previous

Anatomy of a 91% Speedup: Implementing Data Row Patching in Enterprise Web Apps

Next

Designing RBAC and Concurrent Session Controls for Enterprise SaaS


  • Home
  • Writing
  • Lab
  • Resume
  • GitHub
  • LinkedIn
  • X
  • ahmed@aashrafh.me

Open to relocation for Senior+/Lead opportunities

© Ahmed Ashraf