Sitemap

Micro‑frontends in Angular with Native Federation (2025): A Practical, End‑to‑End Guide

7 min readSep 30, 2025

--

TL;DR — Angular’s modern build system (ESM, esbuild/Vite, SSR & hydration) is now the default. Native Federation brings the familiar Module Federation mental model to this toolchain using web standards (ESM + import maps), so teams can ship independently deployed micro‑frontends with fast builds and shared dependencies at runtime.

Table of contents

  • Why micro‑frontends for Angular — now?
  • What is Native Federation (and how it differs from Module Federation)?
  • Reference architecture
  • Quickstart: host + two remotes
  • SSR & incremental hydration (Angular 18+)
  • Sharing dependencies & version strategy
  • Runtime manifests, environments & security
  • Migrating from webpack Module Federation
  • Running Module Federation and Native Federation side‑by‑side
  • Common pitfalls & fixes
  • FAQ
  • References

Why micro‑frontends for Angular — now?

Complex products evolve faster when features are owned by autonomous teams. Micro‑frontends split a UI into independently built/deployed apps (“remotes”) composed at runtime by a shell (“host”), improving team autonomy and release decoupling. Module Federation (webpack 5) popularized this pattern — but Angular v17+ defaults to a faster esbuild/Vite‑powered build with integrated SSR. A bundler‑agnostic approach is therefore more future‑proof — this is where Native Federation shines.

With ESM and import maps, the browser can locate modules and share dependencies at runtime without webpack‑specific glue. Native Federation embraces these standards and integrates directly with Angular’s new Application Builder and dev server, keeping your MFE setup aligned with official CLI improvements.

What is Native Federation (and how it differs from Module Federation)?

Native Federation is a “browser‑native” implementation of the Module Federation mental model for building MFEs. It uses ECMAScript modules (dynamic import()) and import maps to expose and load modules across separately deployed apps, and to share dependencies (e.g., Angular, RxJS) at runtime. No webpack required.

For Angular, Native Federation (package: @angular-architects/native-federation) delegates to the CLI’s Application Builder and dev server—so you stay on the Angular “happy path” (fast builds, SSR/hydration, HMR). Versions track Angular majors; support includes SSR & incremental hydration from Angular 18 onward.

Reference architecture

Press enter or click to view image in full size

At runtime, the host loads a manifest (federation.manifest.json) that maps remote names → remote entry URLs. The Native Federation runtime reads import maps and dynamically loads ESM from remotes; shared dependencies are loaded once and reused.

Quickstart: host + two remotes

Works with Angular 17+ using the Application Builder. If you’re on older CLI builders, see the migration section.

0) Create workspace & apps


# New workspace (no default app)
ng new angular-mf --create-application=false
cd angular-mf

# Host (shell) and two remotes (standalone components)
ng g application shell --routing --standalone
ng g application products --standalone
ng g application checkout --standalone

Standalone components reduce boilerplate and pair well with route‑level lazy loading — ideal for MFEs on modern Angular. [angular-architects-native-federation]

1) Add Native Federation to each app

# Host (dynamic host can discover remotes at runtime)
ng add @angular-architects/native-federation --project shell --type dynamic-host --port 4200

# Remotes
ng add @angular-architects/native-federation --project products --type remote --port 4201
ng add @angular-architects/native-federation --project checkout --type remote --port 4202

The schematic wires the Application Builder + dev server and scaffolds federation.config.js.

2) Expose components from remotes

products/federation.config.js:

const { withNativeFederation, shareAll } =
require('@angular-architects/native-federation/config');

module.exports = withNativeFederation({
name: 'products',
exposes: {
'./ProductList': './src/app/product-list/product-list.component.ts',
},
shared: { ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }) },
// Optional: skip unused RxJS secondary entry points to slim bundles
// skip: ['rxjs/ajax','rxjs/webSocket','rxjs/testing']
});

checkout/federation.config.js:

const { withNativeFederation, shareAll } =
require('@angular-architects/native-federation/config');

module.exports = withNativeFederation({
name: 'checkout',
exposes: {
'./CheckoutWidget': './src/app/checkout-widget/checkout-widget.component.ts',
},
shared: { ...shareAll({ singleton: true, strictVersion: true, requiredVersion: 'auto' }) }
});

The API mirrors Module Federation (exposes, shared, shareAll), but produces ESM + import maps for the runtime.

3) Host manifest & initialization

Create shell/src/assets/federation.manifest.json:

{
"products": "http://localhost:4201/remoteEntry.json",
"checkout": "http://localhost:4202/remoteEntry.json"
}

The manifest enables runtime discovery of remotes (great for “build once, deploy everywhere”).

4) Route to remote components

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

export const routes: Routes = [
{ path: '', component: HomeComponent, pathMatch: 'full' },
{
path: 'products',
loadComponent: () =>
loadRemoteModule('products', './ProductList').then(m => m.ProductListComponent),
},
{
path: 'checkout',
loadComponent: () =>
loadRemoteModule('checkout', './CheckoutWidget').then(m => m.CheckoutWidgetComponent),
},
];

loadRemoteModule() resolves the ESM exports exposed by the remote, honoring import‑map sharing rules.

5) Run locally

ng serve products --port 4201
ng serve checkout --port 4202
ng serve shell --port 4200

The NF serve target delegates to the Angular dev server, so standard options apply. For HTTPS in dev, configure the generated serve-original target with your certs.

Deeper tutorial: Loiane Groner’s 2025 walkthrough covers a similar host/remote setup with NF and standalone components. [Angular mfe’s with native Federation]

SSR & incremental hydration (Angular 18+)

From Angular 18, Native Federation supports SSR and Incremental Hydration. You can pre‑render the host and remotes, then hydrate them on the client while still composing MFEs at runtime — achieving fast TTI without sacrificing team autonomy or deployment independence.

Get Ramalakshmanan’s stories in your inbox

Join Medium for free to get updates from this writer.

Because NF is a thin wrapper around Angular’s Application Builder and dev server, you automatically inherit ongoing SSR/hydration improvements from the CLI team.

Sharing dependencies & version strategy

Native Federation enables singleton sharing (Angular loaded once) and strictVersion checks to avoid silent mismatches. Under the hood, sharing is realized through ESM + import maps, not webpack internals. Keep core framework packages unified when possible; use semver ranges and skip unnecessary secondary entry points to trim bundles.

If you must run multiple versions, import‑map scopes let specific remotes resolve different library versions while the host uses another — use sparingly, as it increases complexity and payload size.

Runtime manifests, environments & security

  • Dynamic remotes: Point federation.manifest.json to environment‑specific URLs so one host build can target staging or production without rebuilding.
  • HTTPS parity in dev: Configure SSL via the serve-original (Angular dev server) target; NF delegates to it.
  • Integrity & trust: Host only trusted remote origins; consider CSP rules and signing your remote assets if compliance requires. (General best practice; complement with MF runtime diagnostics if you run hybrid setups.)

Migrating from webpack Module Federation

A supported path exists to move from webpack MF to Native Federation on the new builder:

  1. Update Angular & CLI to latest.
  2. Remove MF builder from projects (schematic provided).
  3. Migrate to Application Builder (ng update … --name use-application-builder).
  4. Initialize Native Federation and copy over exposes/shared settings (adjust for NF’s ESM/import‑map runtime).

Angular’s official docs describe the new build system and migration options; most apps can migrate automatically, with manual steps for custom builders.

Running Module Federation and Native Federation side‑by‑side

You can initialize both Native Federation and the Module Federation Runtime in the same shell to load a mix of NF‑ and MF‑based remotes. Delegate shared libraries from NF to MF so both worlds reuse the same instances and migrate remotes incrementally. [Combining Federation]

// Hybrid init sketch (host)
import { initFederation as initNF } from '@angular-architects/native-federation';
import { init as initMF } from '@module-federation/enhanced/runtime';

await initNF('/assets/federation.manifest.json');
const shared = /* collect NF shared metadata */;
initMF({ name: 'shell', remotes: [/* ... */], shared }).initializeSharing();

This hybrid approach is ideal when you can’t flip everything to the new builder at once.

Common pitfalls & fixes

  • “unknown remote …” at runtime: Ensure initFederation() runs before bootstrapping and that the manifest path is correct relative to your served app; pre‑rendering or asset path mismatches can trigger this.
  • Selector‑based embedding of remote components: Routing to exposed components is straightforward. Using a remote’s selector directly (as if it were declared locally) isn’t supported the same way as webpack MF; use routing or wrap the remote in a custom element for slot‑style embedding.
  • Builder mismatches during migration: If you used custom webpack builders (e.g., ngx-build-plus), follow the migration guide and ensure your project uses the Application Builder; several issues were resolved in newer plugin releases.

FAQ

Is Native Federation production‑ready?
Yes — the package tracks Angular majors (16 → 20, etc.), integrates with the Application Builder/dev server, and supports SSR/hydration since Angular 18. Always use the release matching your Angular version.

Can I use Nx?
Absolutely. Nx has great MF support (including Dynamic Module Federation). With Angular 17+, you can also adopt NF to stay aligned with the new builder; Nx and Angular Architects tooling are complementary.

How is this different from pure import‑map orchestration?
You can orchestrate MFEs using raw import maps yourself, but NF adds Angular‑specific helpers (e.g., loadRemoteModule) and build/runtime wiring, plus sharing semantics similar to MF—without locking you to webpack.

References

Bonus: one‑liner script to scaffold the example

Paste this in a bash shell; it generates the host and two remotes, adds Native Federation, and sets ports.

# !/usr/bin/env bash
set -e
APP=angular-mf
ng new $APP --create-application=false
cd $APP
ng g application shell --routing --standalone
ng g application products --standalone
ng g application checkout --standalone

ng add @angular-architects/native-federation --project shell --type dynamic-host --port 4200 -y
ng add @angular-architects/native-federation --project products --type remote --port 4201 -y
ng add @angular-architects/native-federation --project checkout --type remote --port 4202 -y

# Manifest for the host
mkdir -p projects/shell/src/assets
cat > projects/shell/src/assets/federation.manifest.json <<'JSON'
{
"products": "http://localhost:4201/remoteEntry.json",
"checkout": "http://localhost:4202/remoteEntry.json"
}
JSON

echo "✅ Scaffold complete. In three terminals run:
ng serve products --port 4201
ng serve checkout --port 4202
ng serve shell --port 4200
Then open http://localhost:4200"

--

--