React Micro Frontend Architecture Tutorial and Guide

Why Micro-Frontends?

Micro frontend architecture is becoming increasingly popular due to its performance benefits and the ability to reduce developer dependencies. By breaking down a monolithic frontend into smaller, independent micro-applications, teams can work on different parts of a project simultaneously, improving scalability and maintainability.

What You Will Learn in This Tutorial

In this guide, we will walk through the process of setting up a micro-frontend architecture using React and Vite. You will learn:

  • How to configure Module Federation with Vite.
  • How to create a remote micro-frontend that exposes components.
  • How to dynamically reuse a remote component in a host application.

Project Use Case: E-Commerce Application

For this tutorial, we will use an e-commerce application as an example. The host application (home app) will consume and display a Featured Products List from the Products Micro-Frontend. This approach showcases how a fully functional component can be shared across multiple applications without duplicating code.

By the end of this tutorial, you will have a clear understanding of how to structure a micro-frontend application with React and Vite, making your micro frontend architecture more flexible and scalable.

Overview of Micro Frontend Architecture for React Applications

Setting Up the Microfrontend Project

Create the Main Directory

mkdir micro-frontend-project
cd micro-frontend-project  

Create two separate Vite projects:

  • Products (Remote App) → Micro-frontend exposing a component.
  • Host (Main App) → Application consuming the remote component.

Setting Up the Remote Products Feature

Step 1: Create the Products Project

npm create vite@latest

  • Enter project name: products
  • Select React
  • Select TypeScript
Expert ReactJS Development for Micro Frontends

Step 2: Install Module Federation Plugin

cd products
npm install @module-federation/vite

Step 3: Implement Product List Feature

1. Create Product List Page:

Create src/pages/ProductsList/ProductsList.tsx to display featured and all products.

import { useEffect, useState } from "react";
import { ProductListItem } from "../../components/ProductListItem/ProductListItem";
import { IProduct } from "../../interfaces/IProduct";
import "./ProductsList.css";
import FeaturedProductsList from "../../components/FeaturedProductsList/FeaturedProductsList";


export const ProductList = () => {
 const [products, setProducts] = useState<IProduct[]>([]);


 useEffect(() => {
   fetchProducts();
 }, []);


 const fetchProducts = async () => {
   try {
     const productsResponse = await fetch("https://dummyjson.com/products");
     const productsResponseJson = await productsResponse.json();
     setProducts(productsResponseJson.products);
   } catch (error) {
     console.log("error", error);
   }
 };


 return (
   <div className="product-list-container">
     <h2>Products</h2>
     <FeaturedProductsList></FeaturedProductsList>
     <h2 className="heading">All Products</h2>
     <div className="products-list">
       {products.map((item) => (
         <ProductListItem product={item}></ProductListItem>
       ))}
     </div>
   </div>
 );
};
Code language: JavaScript (javascript)

Here, we are using a dummy API for the product list.

2. Create Product List CSS:

Create src/pages/ProductsList/ProductsList.css

.products-list {
 display: grid;
 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
 grid-auto-rows: minmax(250px, auto);
}
.product-list-container {
 height: 100vh;
 width: 100%;
 text-align: flex-start;
}Code language: CSS (css)

3. Create Product Interface:

Create src/interfaces/IProduct.ts

export interface IProduct {
 title: string;
 description: string;
 price: string;
 images: string[];
}Code language: CSS (css)

4. Create Product Card Component:

Create src/components/ProductListItem/ProductListItem.tsx

import { IProduct } from "../../interfaces/IProduct";
import "./ProductListItem.css";


interface ProductListItemProps {
 product: IProduct;
}


export const ProductListItem = (props: ProductListItemProps) => {
 const { product } = props;
 return (
   <div className="product-card">
     <div className="product-image-container">
       <img src={product.images[0]} className="product-image"></img>
     </div>
     <h3>{product.title}</h3>
     <h2>{`$ ${product.price}`}</h2>
     <h6>{product.description}</h6>
   </div>
 );
};Code language: JavaScript (javascript)

5. Create Product Card CSS file:

Create src/components/ProductListItem/ProductListItem.css

.product-image {
 width: 120px;
 height: 120px;
}
.product-card {
 background-color: white;
 border-radius: 4px;
 box-shadow: rgba(100, 100, 111, 0.2) 0px 7px 29px 0px;
 padding: 8px;
 margin: 8px;
 min-width: 285px;
}
.product-image-container {
 display: flex;
 justify-content: center;
}Code language: CSS (css)

6. Create Featured Product List Component:

Create src/components/FeaturedProductsList/FeaturedProductsList.tsx

import { useEffect, useState } from "react";
import { IProduct } from "../../interfaces/IProduct";
import { ProductListItem } from "../ProductListItem/ProductListItem";
import "./FeaturedProductsList.css";


const FeaturedProductsList = () => {
 const [featuredProducts, setFeaturedProducts] = useState<IProduct[]>([]);


 useEffect(() => {
   fetchProducts();
 }, []);


 const fetchProducts = async () => {
   try {
     const productsResponse = await fetch('https://dummyjson.com/products?limit=10&skip=10&select=title,price,images,description');
     const productsResponseJson = await productsResponse.json();
     setFeaturedProducts(productsResponseJson.products);
   } catch (error) {
     console.log("error", error);
   }
 };


 return (
   <div>
     <h2 className="heading">Featured Products</h2>
     <div className="featured-product-list">
       {featuredProducts.map((item) => (
         <ProductListItem product={item}></ProductListItem>
       ))}
     </div>
   </div>
 );
};


export default FeaturedProductsList;Code language: JavaScript (javascript)

7. Create Featured Product List CSS file:

Create src/components/FeaturedProductsList/FeaturedProductsList.css

.featured-product-list {
 display: flex;
 flex-direction: row;
 overflow-x: scroll;
}Code language: CSS (css)

8. Use the Products page in the App file:

import './App.css'
import { ProductList } from './pages/ProductsList/ProductsList'


function App() {


 return (
   <>
    <ProductList></ProductList>
   </>
 )
}


export default AppCode language: JavaScript (javascript)

9. Update App.css default CSS:

Update only root css

#root {
 max-width: 1280px;
 padding: 2rem;
 height: 100vh;
}Code language: CSS (css)

10. Update port in the package.json:

...  
"scripts": {
   "dev": "vite --port 3000",
   "build": "tsc -b && vite build",
   "lint": "eslint .",
   "preview": "vite preview --port 3000"
 },
...Code language: JavaScript (javascript)

Step 4: Configure Module Federation

Update vite.config.ts

import { federation } from "@module-federation/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
import { dependencies } from "./package.json";
export default defineConfig(() => {
 return {
   build: {
     target: "chrome89",
   },
   plugins: [
     federation({
       filename: "remoteEntry.js",
       name: "products",
       exposes: {
         "./featured-products":
           "./src/components/FeaturedProductsList/FeaturedProductsList.tsx",
       },
       remotes: {},
       shared: {
         react: {
           requiredVersion: dependencies.react,
           singleton: true,
         },
       },
     }),
     react(),
   ],
 };
});Code language: JavaScript (javascript)
  • filename: "remoteEntry.js": Specifies the entry file for the microfrontend, which other applications can access.
  • name: "products": Defines the unique identifier for this microfrontend.
  • This allows other microfrontends (hosts) to import the FeaturedProductsList component.
  • "./featured-products": This is how the module will be imported remotely.
  • "./src/components/FeaturedProductsList/FeaturedProductsList.tsx": The actual file that gets exposed.

Setting Up the Host Application

Step 1: Create the Host Project

npm create vite@latest

  • Enter project name: host
  • Select React
  • Select TypeScript

Step 2: Install Module Federation Plugin

cd host
npm install @module-federation/vite

Step 3: Implement Home Page

1. Create Home Page:

Create pages/home/Home.tsx

import React, { Suspense } from "react";


const FeaturedProducts = React.lazy(
   // @ts-ignore
   async () => import('products/featured-products'),
);


const Home = () => {
 return (
   <div>
     <h2>Home</h2>
     <Suspense fallback="loading...">
       <FeaturedProducts />
     </Suspense>
   </div>
 );
};


export default Home;Code language: JavaScript (javascript)

Imported Featured Products from Products (Remote app)

2. Update App.tsx

import "./App.css";
import Home from "./pages/home/Home";


function App() {
 return <Home></Home>;
}


export default App;Code language: JavaScript (javascript)

3. Update App.css default CSS:

Update only root css

#root {
 max-width: 1280px;
 padding: 2rem;
 height: 100vh;
}Code language: CSS (css)

Step 4: Configure Module Federation

Update vite.config.ts

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import {federation} from "@module-federation/vite";
import { dependencies } from './package.json';




// https://vite.dev/config/
export default defineConfig({
 build: {
   target: 'esnext',
   minify: false
 },
 plugins: [
   federation({
     name: "app",
     remotes: {
       products: {
         type: 'module',
         name: 'products',
         entry: 'http://localhost:3000/remoteEntry.js',
         entryGlobalName: 'remote',
         shareScope: 'default',
       },
     },
     filename: "remoteEntry.js",     
     shared: {
       react: {
         requiredVersion: dependencies.react,
         singleton: true,
       },
     },
   }),
 
   react(),
 ], 
});Code language: JavaScript (javascript)
  • remotes: Specifies the remote applications (microfrontends) that will be loaded dynamically.
  • products: The key that identifies the remote application.
    • type: 'module': Indicates that the remote entry is an ES module.
    • name: 'products': The unique name of the remote application.
    • entry: 'http://localhost:3000/remoteEntry.js': The remote entry file URL where the microfrontend is hosted.
    • entryGlobalName: 'remote': Specifies a global namespace for the remote module.
    • shareScope: 'default': Ensures dependency sharing across microfrontends.
  • shared: Specifies shared dependencies across microfrontends to avoid duplicate React versions.

Final Steps: Run Both Applications

Run the Remote App (Products)

cd products
npm run dev

On http://localhost:3000/, you can see the featured products and a list of all products.

Running the Remote App for React Micro Frontend Architecture

Run the Host App

cd host 
npm run dev

Now, the Host Application dynamically loads the Featured Products Component from the Products Micro-Frontend using vite module federation 

Running the Host App in React Micro Frontend Architecture

This repository contains the code for the tutorial: “React Micro Frontend Architecture – An in Depth Tutorial With Example“, published by Mobisoft – Web Application Development Company, Houston.

Feel free to download a sample example I’ve created from GitHub to get started.

Conclusion

Micro-frontend architecture is revolutionizing front-end development by enabling teams to work independently on different parts of an application while ensuring seamless integration. In this tutorial, we explored how to set up a micro-frontend architecture using React, Vite, and Module Federation, allowing components to be dynamically shared across multiple applications. 

By implementing a Products Micro-Frontend and a Host Application, we demonstrated how to reuse a fully functional component (Featured Products List) without duplicating code.

This approach makes frontend development scalable, modular, and efficient, reducing dependencies between teams and improving performance. With micro-frontends, applications can be developed and deployed independently, making them easier to maintain and extend over time.

Connect for React Micro Frontend Architecture Consultation

Author's Bio

Chetan Shelake
Chetan Shelake

Chetan Shelake is a Principal Software Engineer at Mobisoft Infotech with 7.5 years of experience in web, mobile, and backend development. Specializing in React, React Native, and Node, he is dedicated to building innovative and user-friendly applications. Chetan is passionate about delivering scalable solutions and staying ahead in emerging technologies.