concept

Runtime Composition Risk

also called Remote Module Risk, Deferred Integration Failure

The class of failures created by resolving module existence, export shape and shared-dependency versions in the user's browser instead of at build time - including the inability to roll back a remote you do not own.

module-federationmicro-frontendsversioningresiliencerollback

A shell application composes three remote modules from three teams at load time. The shell's own build is green. Every check a normal import performs - the module exists, its exports match, its shared dependencies are compatible - has been deferred to the user's browser, on their network, at the moment they need it.

That deferral is the entire trade. It buys independent release timing, and it costs the guarantees the compiler used to provide.

Why it matters

The failures are not exotic, and their default handling is usually absent.

An unreachable remote - a bad deploy, an expired certificate, a CDN region problem - produces an unhandled rejection inside a dynamic import. It is caught by whichever error boundary happens to sit above that subtree, or by nothing, which renders a blank page rather than a degraded one.

An incompatible shared dependency is worse, because it looks fine. If the shell provides a framework as a singleton and a remote was built against a different major version, the failure surfaces as an error deep inside the remote, for the subset of users who reach that route, hours after the deploy that caused it.

And the rollback is not yours. The shell team can see the failure and cannot fix it, because the broken artefact is deployed by another team. You have distributed the release process without distributing the ability to undo a release.

Implementation patterns

  • An error boundary per remote with a designed fallback, not a generic full-page error. The rest of the application should survive one remote's absence.
  • A timeout on the remote load. Slow is more common than unreachable, and a hanging import is a spinner that never resolves.
  • Pinned, versioned remote entry URLs rather than a floating latest. This is the highest-value control: it converts a runtime surprise into a deployment decision the shell team controls, and it restores rollback.
  • Strict singleton declarations with required version ranges, so an incompatible shared dependency fails loudly at resolution rather than quietly inside a hook.
  • Contract tests in the remote's own pipeline that load it into a copy of the shell. Runtime composition removes the compiler's checks; something must replace them.
  • Cache remote entries with short, deliberate TTLs, because a broken entry cached at the edge keeps failing after the fix ships.
  • Alert on remote load failure rate per remote, which nothing provides by default.

Implementation note on scale

The pattern earns its cost at a specific threshold: roughly four or more teams that genuinely release on independent schedules. Below that, build-time composition through published packages gives the same modularity, keeps compile-time verification, and makes rollback a single deploy of the shell.

Industry example

The failure mode is the general one documented across distributed front-end architectures: organisations that adopted runtime-composed micro-frontends and reported, two years later, slower pages, visual inconsistency and harder changes. The mechanism is consistent - shared dependencies are duplicated or mismatched across remotes, the composed page budget is nobody's responsibility, and each team optimises its own remote while the page gets worse. The architecture solved an organisational problem and created a technical one.

Failure scenarios

  • Blank page from one failed remote, because no boundary was placed at the composition point.
  • Version skew in a shared singleton, surfacing as a runtime error in a subset of routes.
  • Duplicate frameworks shipped when singleton sharing is misconfigured, doubling the bundle silently.
  • A remote's deploy breaking the shell in production, with the shell team unable to roll it back.
  • Cached broken entries extending the incident beyond the fix.
  • No composed-page performance budget, so the sum of three well-behaved remotes exceeds any target.

Trade-offs

Choose Gains Pays
Runtime composition Independent release timing across teams Compile-time checks lost · rollback not in your control · runtime failure handling to build
Build-time composition via packages Compile-time verification · single-deploy rollback · one bundle to optimise Coordinated releases; a shell rebuild for every remote change
One application, one team Simplest of all Does not scale past the size where teams contend

Runtime composition buys independent release timing and nothing else. If the organisation does not actually release independently, the cost is being paid for no benefit - which is the most common way this architecture disappoints.

When not to use it

Below roughly four independent teams, or where teams release on a shared cadence anyway. Also when the page has a strict performance budget: composed pages make total bytes nobody's responsibility, and a budget with no owner is not a budget.

And when the consuming and producing teams sit in different organisations with different reliability expectations - the shell inherits every remote's availability, so its effective uptime is the product of all of them. Three remotes at 99.9% each give the composed page about 99.7%, before the shell's own failures.

Interview question

Q: Your team owns a shell that loads four remotes from four teams. You are paged because the dashboard route is blank for some users. Walk me through the investigation and then tell me what you would change so that this class of failure degrades instead of breaking.

What a strong answer covers: checking remote entry load failures per remote and per region first, since the shell's own build is fine · distinguishing unreachable from incompatible, because they have different signatures - a network failure at import versus an error inside the remote's own code · the immediate mitigation, which is pinning the shell to a previous known-good remote entry, and why that is only possible if URLs are versioned · the structural changes: a boundary and a timeout per remote, strict singleton version requirements, contract tests in each remote's pipeline, and a load-failure alert · and the honest observation that the shell's availability is the product of its remotes', which may mean the composition boundary is in the wrong place.

Quick check

Quiz: Why does runtime composition remove your ability to roll back? Because the failing artefact is deployed by another team from another pipeline. Pinning a versioned remote entry URL in the shell is what restores the control.

Flashcard: What does runtime composition actually buy? — Independent release timing, and nothing else. If teams do not release independently, the cost is paid for no benefit.