Skip to content

Angular MFE Remote Configuration | Advanced Setup

Once your host app and remotes are wired up with static remoteEntry.js URLs, the next problem shows up fast: those URLs are different in every environment, and hardcoding them means a rebuild for every deployment target. This guide covers configuring remotes dynamically instead.

Instead of baking remote URLs into webpack.config.js at build time, load them at runtime from environment-specific config:

// remote-manifest.json (deployed alongside the host, swapped per environment)
{
"userDashboard": "https://mfe-user-dashboard.azurestaticapps.net/remoteEntry.js",
"transactionHistory": "https://mfe-transaction-history.azurestaticapps.net/remoteEntry.js"
}
// main.ts β€” fetch the manifest before bootstrapping
import { loadManifest } from '@angular-architects/module-federation';
loadManifest('/assets/remote-manifest.json')
.then(() => import('./bootstrap'))
.catch(err => console.error(err));

The host’s compiled bundle never needs to know the real URLs β€” only the manifest file (a plain JSON asset, swappable without a rebuild) does.

environment.ts
export const environment = {
production: false,
remoteManifest: '/assets/remote-manifest.dev.json'
};
// environment.prod.ts
export const environment = {
production: true,
remoteManifest: '/assets/remote-manifest.prod.json'
};

Each environment’s manifest points at that environment’s actual deployed remotes β€” dev host loads dev remotes, staging loads staging remotes, without touching application code.

Two independent teams shipping to the same remote name is a recipe for a host suddenly loading an incompatible version. Options, in increasing order of safety:

  1. Version in the URL path: https://mfe-user-dashboard.example.com/v2/remoteEntry.js β€” old hosts keep working against /v1/ until they’re explicitly updated.
  2. Version in the manifest, not the remote: keep the remote’s URL stable, but pin which manifest each host environment loads β€” rolling back is then a manifest swap, not a remote redeploy.
  3. Shared dependency version negotiation: shareAll({ strictVersion: true }) (already in your webpack.config.js from the Module Federation setup) fails loudly at load time on an Angular/RxJS version mismatch, rather than producing a subtle runtime bug.

A remote that’s down shouldn’t take the whole host app down with it:

{
path: 'transactions',
loadComponent: () =>
loadRemoteModule({
remoteEntry: environment.remotes.transactionHistory,
remoteName: 'transactionHistory',
exposedModule: './Component'
})
.then(m => m.TransactionHistory)
.catch(() => import('./fallback/remote-unavailable.component').then(m => m.RemoteUnavailableComponent))
}

Route-level .catch() on the loadComponent promise is the simplest guard β€” it swaps in a small β€œthis feature is temporarily unavailable” component instead of an unhandled navigation error.