Carlos Cifuentes
Micro-frontends · Dependencies

Shared dependencies and versions in micro-frontends

Sharing dependencies keeps a micro-frontend platform fast and consistent. It is also the tightest coupling between teams that the architecture leaves in place, so it needs explicit rules.

By Carlos Cifuentes · Frontend architect · Updated 2026-10-02

Why sharing exists

Without sharing, every remote bundles its own copy of Angular, RxJS and the component library. Users download the same code several times. Worse, libraries that hold state end up with several instances: two routers, two copies of the auth service, each with a different idea of the current user.

With sharing, the host and the remotes declare which packages they have in common. Each package is loaded once and reused by everyone.

Singletons

Some libraries must exist exactly once per page:

  • The framework: @angular/core, @angular/common, @angular/router.
  • Libraries with global state: the auth library, shared platform services, usually rxjs.

These are declared as singletons. With the Angular federation plugins from @angular-architects, a typical configuration is:

shared: {
  ...shareAll({
    singleton: true,
    strictVersion: true,
    requiredVersion: 'auto'
  })
}

requiredVersion: 'auto' reads the accepted version range from the project's package.json. strictVersion turns a mismatch into an error instead of a warning.

What happens on a version mismatch

Each application declares the version it provides and the range it accepts. At runtime the federation layer compares them. There are three possible outcomes:

ConfigurationResult when the range is not satisfied
Not a singletonThe remote loads its own copy. Safe for stateless libraries, and it costs extra bytes
Singleton, not strictThe one loaded version is used anyway, with a console warning. It may work, or fail in ways that are hard to trace
Singleton, strictA runtime error when the dependency is requested

A strict singleton that fails loudly is the safer choice for the framework. The details differ between Module Federation and Native Federation, compared in Module Federation vs Native Federation, but the outcomes are similar.

A version policy teams can follow

  • The framework major version is a platform decision. All remotes that share Angular run the same major version. Code compiled for one major version is not guaranteed to run on the runtime of another.
  • Upgrades have a window. The platform team announces the target version and a date. Remotes prepare and switch within the window.
  • Share less. Share the framework, stateful libraries and the design system. Small utilities can be bundled by each remote. Sharing everything in package.json is convenient, and it couples every team to every version.
  • Check in CI. A pipeline step compares each remote's dependency versions against the platform policy and fails the build when they drift.

Running different framework versions side by side

Sometimes one page must run two versions: during a migration, when one team is behind on upgrades, or when a part uses another framework.

The working approach is to stop sharing the framework for that part:

  1. The remote bundles its own framework copy and bootstraps its own application instance. It is not loaded as lazy routes of the host router.
  2. It is wrapped as a custom element, for example with @angular/elements. The host places a tag and passes data through attributes and events.
  3. zone.js patches browser APIs globally, so it should load once. Every Angular version on the page has to work with that single copy.
  4. For parts that cannot share a page safely, such as an AngularJS app that relies on globals, an iframe is the fallback. See Running a legacy app inside a micro-frontend host.

The costs: more bytes, more memory, no shared dependency injection, and two routers to coordinate.

Treat side-by-side versions as a temporary state with an exit date. A platform where every remote runs its own framework version has the costs of micro-frontends and the bundle size of several applications.

Isolation strategies

Sharing a page means sharing more than packages. A few conventions prevent most collisions:

  • CSS. Keep styles scoped to components, which is Angular's default. Prefix any global class with the remote's name.
  • Globals. No writes to window outside a small, namespaced contract.
  • Custom element names. Include a team prefix. A name can be registered only once per page.
  • Storage keys. Prefix localStorage and sessionStorage keys per remote.

Style isolation is covered in more depth in A design system across micro-frontends.

Checklist

  1. Is there a written list of shared packages, and which of them are singletons?
  2. Does a framework version mismatch fail loudly in a test environment?
  3. Does CI check each remote against the version policy?
  4. Does every side-by-side version have an owner and a removal date?
  5. Has the effect on bundle size been measured? See Micro-frontend performance.

More in this section

Planning a migration or a micro-frontend platform?

In a 20-minute call you describe your situation and I tell you how I'd approach it. If it isn't worth doing yet, I'll say so.

Message me on LinkedIn