
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.

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

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 App
Code 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.

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

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.

Author's Bio

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.