Hello, I am Benjy, a newbie in front end. Below will be my take on mircro front end architecture.
What is Micro Front-end?
Microfrontend is an architecture inspired by microservice. What is microservice? Long words short, microservice is a backend architecture that has an API gateway redirect request to respective services.
As what I said just now, microfrontend is conceptually inspired from microservice, hence they somehow look similar.
Micro frontends are an architectural approach that breaks large, monolithic web applications into smaller, independent, and specialized frontend modules.
A master/shell app will act as a container to contain all the microfrontends. Now, the master app will act as a "gateway" to redirect user or to decide which microfrontend to be rendered.
Why Microfrontend?
Imagine today you are setting up a web app for your company to manage internal resources. You started with payroll module, then your web app will look something like this:
Then, your boss wanted to include a leave system. So, you add in the leave module, and a sidebar for user to navigate between modules:
Moving on, your boss wanted to add in more modules, then your web app will look something like:
As your system grows, the codebase become larger and larger. Each iteration will consume more development, testing and deployment effort. Also, the growing codebase will become difficult to maintain.
Hence, microfrontend comes into the rescue. You split related modules into different sub-modules, each maintained in different microfrontend repo. Then, you have a master app combining each of the microfrontends (submodules).
Now, the system become granular and easy to maintain and test. You reduce maintenence effort and earn yourself a promotion (yay!).
Key Characteristics & Benefits of microfrontend:
- Independent Deployment: Teams can release updates to their specific feature (e.g., checkout) without redeploying the entire application.
- Technology Agnostic: Teams can choose or upgrade their own stack (React, Angular, Vue) without coordinating with others, allowing for gradual updates.
- Autonomous Teams: Organized around business domains rather than technical layers, enabling faster development cycles.
- Improved Scalability: Large, complex frontend codebases become easier to manage by breaking them down into manageable pieces.
But,
Microfrontend has its drawbacks too. For example, how to manage shared states between sub-modules? How to ensure UI unity? How can sub-modules communicate with each other? And many more ......
These are the things you need to consider when deciding between monolithic and microfrontends architecture. When your project is small, monolithic is good enough. Evaluate the effort before making decision.
How Microfrontends Work (Basic Idea)
Each microfrontend is built and deployed independently, usually as static assets (JavaScript, CSS) hosted on a server.
The main application dynamically loads these assets at runtime and integrates them into the page by calling a predefined interface (e.g., a mount function).
A Simple Implementation (Concept Demonstration)
This is a simplified implementation for learning purposes and does not handle real-world concerns such as dependency sharing, style isolation, or performance.
Sub App
Lets start with creating a new react project using Vite
In terminal, run:
npm create vite@latest react-app -- --template react
You will see:
The page is too complicated to me, I simplify the page into:
main.jsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<App />
</StrictMode>,
)
App.jsx
import { useState } from 'react'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<div className="sub-app-container-1">
<button
className="count-btn"
onClick={() => setCount((prev) => prev + 1)}
>
Count: {count}
</button>
<button
className="reset-btn"
onClick={() => setCount(0)}
>
reset
</button>
</div>
)
}
export default App
App.css
.sub-app-container-1 {
background: linear-gradient(90deg,rgba(42, 123, 155, 1) 0%, rgba(87, 192, 199, 1) 50%, rgba(83, 232, 237, 1) 100%);
padding: 8px;
display: flex;
flex-direction: column;
gap: 12px;
justify-content: center;
align-items: center;
height: 100%;
}
.count-btn {
background: yellow;
padding: 6px 12px;
border-radius: 4px;
border: 2px solid gray;
font-size: larger;
}
.count-btn:hover {
cursor: pointer;
}
.reset-btn:hover {
cursor: pointer;
}
Now my react app looks like this (a very simple website with counting function)
Let's proceed to the server.
Server
Let's create an express.js server to store our built file from sub app.
In terminal:
mkdir server
cd server
npm init -y
npm install express
Then initiate your repo like this:
app.js
const express = require('express');
const cors = require('cors');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 3000;
app.use(cors());
app.use(express.static(path.join(__dirname, 'static')));
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(PORT, () => {
console.log(`Server is running at http://localhost:${PORT}`);
console.log(`Static path: ${path.join(__dirname, 'static')}`)
});
Then, start your server in terminal:
node app.js
And you will see something like this:
Go back to your react repo and build it
npm run build
You will see the built file under /dist/assets
Copy the .js and .css files and paste them into server/static
To test whether are these files accessible, you can try to access them in browser:
http://localhost:3000/index-CX8UIe2c.js
http://localhost:3000/index-CX8UIe2c.css
You will see something like this:
If you are able to access both file, we can proceed to the main app.
Main App
Let's create main/index.html
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Micro FE Demo</title>
<style>
#root {
width: 80%;
border: 2px solid red;
height: 600px;
}
h1 {
font-size: larger;
font-weight: bold;
}
</style>
</head>
<body>
<h1>I am main app, below is sub app</h1>
<div id="root">
</div>
<script>
</script>
</body>
</html>
Note:
We have to name our sub-app container's id to #root, because React app will mount on #root by default. Normally, this is not the standard practice to hard-code the container's id name. But since this is a demo, we will not go deep into this.
Run the index.html (main app):
And you will see something like this:
Then, here's the magic happens. We will try to make request to the server to get the build files, and mount into our main app.
We will implement the process above in <script>.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Micro FE Demo</title>
<style>
#root {
width: 80%;
border: 2px solid red;
height: 600px;
}
h1 {
font-size: larger;
font-weight: bold;
}
</style>
</head>
<body>
<h1>I am main app, below is sub app</h1>
<div id="root">
</div>
<script>
fetch("http://localhost:3000/index-CX8UIe2c.js")
.then(res => {
return res.text()
})
.then((text) => {
eval(text)
})
fetch("http://localhost:3000/index-CKZWWwUF.css")
.then(res => {
return res.text()
})
.then(text => {
const dom = document.createElement("style");
dom.textContent = text;
document.body.appendChild(dom)
})
</script>
</body>
</html>
AND.......... tada!
You have successfully implemented microfrontend from scratch.
Conclusion
In this note, we explored micro frontend architecture from first principles — what it is, why it exists, and how it works under the hood. By breaking a large monolithic frontend into independently deployable modules, teams gain flexibility, autonomy, and a more manageable codebase as the system scales.
The demo above is deliberately simplified. In practice, you would want to address concerns like:
- Style isolation — using Shadow DOM or CSS scoping to prevent style leakage between sub-apps
- Shared dependencies — avoiding duplicate bundles (e.g., two copies of React) using tools like Webpack Module Federation
- State synchronization — using a shared event bus or a state manager accessible to all sub-apps
- Routing — coordinating navigation between the shell app and sub-apps
Tools like Webpack Module Federation, Single-SPA, and Qiankun solve these problems in production-grade setups and are worth exploring next.
As with any architectural decision, microfrontends are not a silver bullet. For small projects, a well-structured monolith is simpler and easier to reason about. Reach for microfrontends when team autonomy, independent deployability, or codebase scale genuinely demands it.
Thanks for your time. Cheers! :D




















Top comments (0)