<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mayur Kulkarni</title>
    <description>The latest articles on DEV Community by Mayur Kulkarni (@mayur_kulkarni_126).</description>
    <link>https://dev.to/mayur_kulkarni_126</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3377531%2F967411a3-3062-4b4b-bafc-4f5c3131cc33.png</url>
      <title>DEV Community: Mayur Kulkarni</title>
      <link>https://dev.to/mayur_kulkarni_126</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mayur_kulkarni_126"/>
    <language>en</language>
    <item>
      <title>Step-by-Step Guide to Angular Microfrontends with Nx and Dynamic Module Federation</title>
      <dc:creator>Mayur Kulkarni</dc:creator>
      <pubDate>Wed, 30 Jul 2025 15:26:11 +0000</pubDate>
      <link>https://dev.to/mayur_kulkarni_126/step-by-step-guide-to-angular-microfrontends-with-nx-and-dynamic-module-federation-2e04</link>
      <guid>https://dev.to/mayur_kulkarni_126/step-by-step-guide-to-angular-microfrontends-with-nx-and-dynamic-module-federation-2e04</guid>
      <description>&lt;p&gt;In this article, we'll walk through how to implement a scalable Microfrontend architecture in Angular using Webpack Module Federation with Nx, with a focus on Dynamic Module Federation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Microfrontend?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Microfrontend&lt;/strong&gt; is an architectural approach where a large frontend application is broken down into &lt;strong&gt;smaller, independent, self-contained apps&lt;/strong&gt; — similar to how microservices work on the backend.&lt;/p&gt;

&lt;p&gt;Each smaller app (called a &lt;strong&gt;remote&lt;/strong&gt;) represents a specific business domain or UI section — for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;login&lt;/code&gt; page&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;products&lt;/code&gt; page&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;cart&lt;/code&gt; or &lt;code&gt;profile&lt;/code&gt; section&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These micro apps can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Be developed by &lt;strong&gt;different teams&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Be &lt;strong&gt;deployed independently&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Use different release cycles&lt;/li&gt;
&lt;li&gt;Be dynamically &lt;strong&gt;loaded at runtime&lt;/strong&gt; by a central shell app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;What is a Host App?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;host&lt;/strong&gt; is the main application — the shell or container — that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Loads one or more remote apps at runtime&lt;/li&gt;
&lt;li&gt;Manages global routing, layout, or shared services (like authentication or navigation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of it like a dashboard or entry point where all microfrontends come together to form a complete UI.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is a Remote App&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;remote&lt;/strong&gt; is a microfrontend — a standalone Angular app that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Has its own routing and components&lt;/li&gt;
&lt;li&gt;Can be developed/tested independently&lt;/li&gt;
&lt;li&gt;Is exposed to the host using &lt;strong&gt;Webpack Module Federation&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The host consumes the remote app’s UI and logic as if it were a part of its own application — but without tight coupling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In This Project Example&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Host App: &lt;code&gt;dashboard&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Acts as the entry point for the user&lt;/li&gt;
&lt;li&gt;Loads other microfrontend apps dynamically&lt;/li&gt;
&lt;li&gt;Has shared layout and routing logic&lt;/li&gt;
&lt;li&gt;Reads the manifest file to dynamically load remote apps at runtime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Remote App: &lt;code&gt;login&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Contains a simple login form and logic&lt;/li&gt;
&lt;li&gt;Can be developed and deployed independently&lt;/li&gt;
&lt;li&gt;Is exposed to the host using Module Federation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The host (&lt;code&gt;dashboard&lt;/code&gt;) loads the remote (&lt;code&gt;login&lt;/code&gt;) using Dynamic Module Federation. &lt;/p&gt;

&lt;p&gt;When the user navigates to /login, the host dynamically loads the remote login app and renders its content as if it were a part of the host.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnkb0ngmwr4j2npdp7il.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgnkb0ngmwr4j2npdp7il.png" alt=" " width="800" height="182"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is Nx&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nx is a powerful tool for building and managing monorepos — where you keep multiple frontend and backend apps, libraries, and shared code in a single workspace.&lt;/p&gt;

&lt;p&gt;It helps you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate apps and libraries quickly&lt;/li&gt;
&lt;li&gt;Share code easily across projects&lt;/li&gt;
&lt;li&gt;Speed up builds with smart caching&lt;/li&gt;
&lt;li&gt;Scale large codebases efficiently&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What are advantages of using Nx for creating microfrontends&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simplified setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nx provides powerful generators (nx g @nx/angular:host, remote, etc.) that automate the boilerplate for setting up Webpack Module Federation, routing, and lazy loading — saving a lot of time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monorepo Support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nx is built for monorepos, allowing you to manage multiple microfrontend apps and shared libraries in one workspace. This helps with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better code sharing&lt;/li&gt;
&lt;li&gt;Easier dependency tracking&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Consistent tooling&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatic Dependency Sharing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you use shared libraries (like an auth service), Nx automatically configures Module Federation sharing so they’re not duplicated across remotes — no manual Webpack config needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Faster Builds with Caching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nx uses smart build and test caching — if nothing has changed in a remote, it skips rebuilding it. This makes development and CI/CD pipelines faster.&lt;/p&gt;

&lt;p&gt;And many more advantages...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is static and dynmaic module federation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When building Microfrontends with Angular and Nx, the host app (like dashboard) needs to know where the remote apps (like login) are located.&lt;/p&gt;

&lt;p&gt;There are two ways to do this: Static and Dynamic.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Static Module Federation (Build-time URL)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In Static Federation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The remote app (login) is hardcoded in the host (dashboard) during the build.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;That means: if the remote URL changes (for example, from &lt;a href="http://localhost:4201" rel="noopener noreferrer"&gt;http://localhost:4201&lt;/a&gt; to &lt;a href="https://staging.example.com/login" rel="noopener noreferrer"&gt;https://staging.example.com/login&lt;/a&gt;), you must rebuild the host app to update the URL.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In This Project:&lt;/p&gt;

&lt;p&gt;When we'll first create the dashboard and login apps using Nx generators, the host will be configured statically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remotes: ['login']  // Nx internally resolves to http://localhost:4201
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works fine locally — but when deploying to staging or production, it becomes a problem.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dynamic Module Federation (Runtime URL)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Dynamic Federation solves this.&lt;/p&gt;

&lt;p&gt;Instead of hardcoding the remote URL, the host app (dashboard) loads the remote (login) dynamically at runtime using a small JSON file like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// module-federation.manifest.json
{
  "login": "https://staging.example.com/login"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, you don’t need to rebuild the host.&lt;br&gt;
You just change the manifest file depending on the environment.&lt;/p&gt;

&lt;p&gt;In This Project:&lt;br&gt;
We updated the main.ts of the dashboard app like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch('/module-federation.manifest.json')
  .then(res =&amp;gt; res.json())
  .then(setRemoteDefinitions)
  .then(() =&amp;gt; import('./bootstrap'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For real-world use (like CI/CD, multiple environments), always go with Dynamic Federation.&lt;br&gt;
For learning or small apps, Static is fine to start with.&lt;/p&gt;

&lt;p&gt;Let's begin to create. We'll create following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Host app (dashboard) – loads other apps&lt;/li&gt;
&lt;li&gt;A Remote app (login) – login form&lt;/li&gt;
&lt;li&gt;Shared logic (user-auth service)&lt;/li&gt;
&lt;li&gt;Then convert this setup to &lt;strong&gt;Dynamic Module Federation&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step-by-Step: Building Microfrontends with Nx&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Create Nx Workspace&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-nx-workspace@latest ng-mf --preset=apps
cd ng-mf
npx nx add @nx/angular
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the Host App (Static Setup First)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nx g @nx/angular:host apps/dashboard --prefix=ng-mf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the Remote App (Login)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nx g @nx/angular:remote apps/login --prefix=ng-mf --host=dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After creating the apps, if you check module-federation.config.ts in both, you can see:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the Host (dashboard)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const config: ModuleFederationConfig = {
  name: 'dashboard',
  remotes: ['login'],
};

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;remotes&lt;/code&gt;: Lists the remote apps to load (e.g., login).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In the Remote (Login)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const config: ModuleFederationConfig = {
  name: 'login',
  exposes: {
    './Routes': 'apps/login/src/app/remote-entry/entry.routes.ts',
  },
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;exposes&lt;/code&gt;: Defines what the remote shares with the host — like routes or components.&lt;/p&gt;

&lt;p&gt;Create Shared Library&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nx g @nx/angular:lib libs/shared/data-access-user
nx g @nx/angular:service user --project=data-access-user

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a User service using RxJS BehaviorSubject to track login state&lt;/p&gt;

&lt;p&gt;Add Login Form in Login Remote&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;In apps/login/src/app/remote-entry/entry.ts, add a login form UI and inject User service.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update Dashboard App&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show login form if user is not authenticated.&lt;/li&gt;
&lt;li&gt;Show dashboard content if user is logged in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add route (in apps/dashboard/src/app/app.routes.ts):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  path: 'login',
  loadChildren: () =&amp;gt; import('login/Routes').then(m =&amp;gt; m.remoteRoutes),
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where dashboard (host) loads login (remote).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Converting Static Federation to Dynamic&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;a. Create a manifest file&lt;br&gt;
apps/dashboard/public/module-federation.manifest.json&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "login": "http://localhost:4201"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;b. Update main.ts in dashboard&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fetch('/module-federation.manifest.json')
  .then(res =&amp;gt; res.json())
  .then(definitions =&amp;gt; setRemoteDefinitions(definitions))
  .then(() =&amp;gt; import('./bootstrap'));

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;c. Remove remotes: ['login'] from module-federation.config.ts&lt;/p&gt;

&lt;p&gt;d. Update route loading&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;loadChildren: () =&amp;gt;
  loadRemoteModule('login', './Routes').then((m) =&amp;gt; m.remoteRoutes),

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Serve the app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nx serve dashboard --devRemotes=login // To start host app and link it with login app (which is remote app) 

nx serve login // To start login app separately
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the complete code implementation (including dashboard and login content), please refer my below github repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mayurkulkarni126/dynamic-module-federation-nx" rel="noopener noreferrer"&gt;GitHub repository for this project&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's next?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Try implementing your own host app&lt;/li&gt;
&lt;li&gt;Try adding a second remote app (e.g. &lt;code&gt;profile&lt;/code&gt;, &lt;code&gt;cart&lt;/code&gt;, or &lt;code&gt;settings&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Deploy remotes to different environments and update the manifest to test runtime switching&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for reading! &lt;/p&gt;

</description>
      <category>nx</category>
      <category>angular</category>
      <category>webpack</category>
      <category>microfrontend</category>
    </item>
  </channel>
</rss>
