Micro‑frontends in Angular with Native Federation (2025): A Practical, End‑to‑End Guide
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
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 --standaloneStandalone 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 4202The 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 4200The 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.jsonto 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:
- Update Angular & CLI to latest.
- Remove MF builder from projects (schematic provided).
- Migrate to Application Builder (
ng update … --name use-application-builder). - Initialize Native Federation and copy over
exposes/sharedsettings (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
- Native Federation (Angular Architects): npm & README (features, versions, SSR/hydration, builder integration) [@angular-architects-native-federation-npm]
- Angular CLI — new build system (v17+): esbuild/Vite, SSR/prerender, migration guidance [Migrating Angular], [Getting started with esbuild system]
- Announcement (17.1): NF delegates to Application Builder & dev server; philosophy and upgrade notes [announcing-native-federation-for-angular-17]
- Config deep‑dive: Exposes, shared, skip lists, runtime/manifest mechanics (DeepWiki) [Native Federation]
- Import maps + MFEs: Browser‑native orchestration, scopes, versioning [you-might-not-need-module-federation-orchestrate-your-microfrontends], [micro-frontends-with-native-federation]
- Hybrid NF + MF: Side‑by‑side runtime & migration pattern [Combining Federation]
- Tutorial: Creating Angular micro‑frontends with NF (2025) [Creating angular apps with native Federation]
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"






