federation-js: Runtime Module Federation

federation-js is the small runtime that loads federated modules in the browser. It resolves shared dependencies by semver range, so versions can coexist.

Updated Oct 25, 2026 Edit this page on GitHub

Runtime for JavaScript module federation, built on a SystemJS-style module registry.

FynMesh: Website · Demo · Shell demo

This is the piece that runs in the browser. It resolves shared modules across independently built and deployed bundles, keeps a single instance of a shared dependency when asked to, and lets one bundle load modules exposed by another.

Containers are normally generated for you by rollup-plugin-federation — you rarely construct one by hand.

Install

npm install federation-js

The module loader

federation-js is half of a pair. It does not carry a module registry of its own — it expects a System global, and it must be the fork of SystemJS this package ships, not stock SystemJS. The fork keeps the module registry, name→url, url→module and per-version qualifiers in System.registrations; stock SystemJS has no such thing, and a crossed pair fails in ways that look like federation bugs.

Both loader builds are in this package's dist, so load one before the runtime:

<!-- development: readable, keeps the long-form diagnostics -->
<script src="/node_modules/federation-js/dist/system.js"></script>
<script src="/node_modules/federation-js/dist/federation-js.dev.js"></script>
<!-- production -->
<script src="/node_modules/federation-js/dist/system.min.js"></script>
<script src="/node_modules/federation-js/dist/federation-js.min.js"></script>

Keep the two halves on the same build: system.js with federation-js.dev.js, system.min.js with federation-js.min.js.

Runtime

Importing the runtime installs a Federation instance on the global object:

import "federation-js/runtime";

// load a container and pull an exposed module out of it
Federation.import("__mf_container_plugin_1")
  .then((container) => container.get("./bootstrap"))
  .then((getModule) => console.log("module", getModule()));

A shared module is retrieved the same way, by the name it was shared under:

Federation.import("__mf_container_plugin_1")
  .then((container) => container.get("react"))
  .then((getModule) => console.log("module", getModule()));

A container that only consumes a shared module can still resolve it, provided some container that shares it has already loaded.

Debugging a minified page

Federation.__I() returns a snapshot of what the runtime decided about shared-module resolution: for every chunk and share key, the importer-declared ranges, the ranges resolution actually applied, and the versions this runtime's own semver accepts. It is in the minified build too — that is the build it exists for, since the same information is readable off $SS and $SC in a development one. The result is a versioned envelope, { v: 1, r: [...] }; check v before reading the rest.

The name is __I because nobody guesses it, which is the intent: it is a debugging hatch, not part of the API a container or the loader talks to.

Combined module files

Several modules can be shipped in one physical file. Each still registers itself under its own filename, so nothing about importing it changes — the file it arrived in is not part of its identity. A module built into a combined file carries b (the physical file) alongside f (itself); when they differ, the runtime derives the module's own url from f rather than from document.currentScript, which would otherwise be the same for every module in the file.

Two ways a combined file gets used:

  • Already loaded — a plain <script> tag is enough. Every module in it registers, and a later import of any of them resolves without a request.
  • Not loaded yet — the container entry declares which file carries which modules (Federation._B(map, container, version)), and the first import of any member pulls that file once, however many members ask at the same time. If the file turns out not to carry the module it claimed, the runtime warns and loads that module's own file instead.

Pulling a file registers its modules; it does not execute them. A module's body still runs on first import, exactly once.

Producing these files is a build concern — see rollup-plugin-federation's federation-combine.

Entry points

Import Contents
federation-js Container class and the public types
federation-js/runtime the runtime; installs the global Federation
federation-js/container Container on its own
federation-js/types types on their own

Shared-module resolution is semver aware: a container declares the range it accepts, and the runtime picks a loaded version that satisfies it, falling back to loading its own copy when nothing matches.

License

Apache-2.0