Getting Started

Applies to

Install the adapter, run ng add on every project that should participate in the federation, and you have a working host + remote pair within minutes. This page walks the happy path; the Tutorial goes through a complete example.

See native-federation in action — Tractor Store demo

A complete Native Federation Angular host with multiple remotes, deployed and live — clone or fork the source from native-federation/playground to run it locally.

Open the demo →

Source on GitHub: native-federation/playground.

1. Install

npm i @angular-architects/native-federation -D

Which package? From Angular 22 the adapter is back under its original name, @angular-architects/native-federation (22.x). If you are still on Angular 20 or 21, install @angular-architects/native-federation-v4 instead — it is the exact same adapter, only the package name differs, so substitute -v4 in every command and import on these pages. Pin the adapter to the same major as your Angular CLI.

Your Angular Install
22+ @angular-architects/native-federation
20 – 21 @angular-architects/native-federation-v4

The package brings @softarc/native-federation (^4.0.0) and @softarc/native-federation-orchestrator (^4.0.0) as dependencies. The ng add step below adds es-module-shims, @angular-devkit/build-angular and @softarc/native-federation-orchestrator (as a devDependency) on top — nothing else to install up front.

2. Scaffold a Remote (Micro Frontend)

ng g @angular-architects/native-federation:init --project mfe1 --port 4201 --type remote

This runs the init schematic against mfe1. See Schematics → init for the full list of changes; in summary it:

3. Scaffold a Host (Shell)

ng g @angular-architects/native-federation:init --project shell --port 4200 --type dynamic-host

The same schematic runs in dynamic-host mode for the shell. In addition to the changes above, it creates a federation.manifest.json in the project's public/ (or src/assets/) folder listing the remotes it knows about:

{
  "mfe1": "http://localhost:4201/remoteEntry.json"
}

Pick the type that fits the role of the project:

--type What you get When to use it
remote main.ts calls initFederation({ '<name>': './remoteEntry.json' }) — exposes its own remoteEntry.json. Every Micro Frontend.
host Remote map is inlined in main.ts. Single-environment shells where remote URLs never change.
dynamic-host main.ts reads from federation.manifest.json. The default for shells — swap the manifest per environment without rebuilding.

4. Wire a Lazy Route in the Host

Loading a remote module is plain Angular lazy-loading with loadRemoteModule in place of a dynamic import(). On v4 the schematic wires the orchestrator directly — the generated main.ts initialises federation, then dynamically imports your Angular bootstrap:

// projects/shell/src/main.ts (generated)
import { initFederation } from '@softarc/native-federation-orchestrator';
import {
  useShimImportMap,
  consoleLogger,
  globalThisStorageEntry,
} from '@softarc/native-federation-orchestrator/options';

initFederation('/assets/federation.manifest.json', {
  ...useShimImportMap({ shimMode: true }),
  logger: consoleLogger,
  storage: globalThisStorageEntry,
  hostRemoteEntry: './remoteEntry.json',
  logLevel: 'debug',
})
  .catch(err => console.error(err))
  .then(_ => import('./bootstrap'))
  .catch(err => console.error(err));

With that generated bootstrap, routes use the loadRemoteModule re-exported from the adapter package:

// projects/shell/src/app/app.routes.ts
import { Routes } from '@angular/router';
import { loadRemoteModule } from '@angular-architects/native-federation';

export const routes: Routes = [
  {
    path: 'flights',
    loadComponent: () =>
      loadRemoteModule('mfe1', './Component').then(m => m.AppComponent),
  },
];

That top-level loadRemoteModule is convenient but deprecated. For the recommended pattern — taking loadRemoteModule off the resolved initFederation promise and threading it through Angular's DI — see Runtime.

5. Run It

ng serve mfe1 -o   # in one terminal
ng serve shell -o  # in another

The shell's dev server proxies http://localhost:4201/remoteEntry.json at request time and lazy-loads the remote when the route is hit. The Angular adapter's dev server also serves the federation artifacts (shared bundles, exposed modules) directly from dist/<project>/browser, so you don't need a separate static server.

What Got Generated

After running ng add against a project, expect the following layout:

projects/mfe1/
├── federation.config.mjs         ← shared/exposes config (see Angular Config)
├── tsconfig.federation.json      ← extends tsconfig.json, used only by the federation builder
└── src/
    ├── main.ts                   ← initFederation(...) bootstrap (orchestrator by default)
    └── bootstrap.ts              ← the *original* Angular bootstrap (bootstrapApplication etc.)

And in the workspace root:

angular.json    ← build → @angular-architects/native-federation:build
                ← serve → @angular-architects/native-federation:build
                ← esbuild → @angular/build:application (the original build)
                ← serve-original → @angular/build:dev-server (the original serve)
package.json    ← + es-module-shims, + @softarc/native-federation-orchestrator (devDep)

Production Builds

ng build mfe1
ng build shell --configuration production

Each project's output (dist/<project>/browser/) contains a remoteEntry.json alongside the Angular bundle. Deploy the whole folder as a static site; the host's manifest only needs to point at the matching remoteEntry.json URL.

The shape of remoteEntry.json, the import map and the artifact cache are all produced by the core. See Build Artifacts for the full layout.

Next Steps