Shared State & Routing Between MFEs
Share a global event bus or context across micro-frontends and coordinate client-side routing.
Shared State & Routing Between MFEs is a free React Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the React Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The State Sharing Challenge
Micro-frontends in different bundles cannot directly share React state or context. They need alternative strategies: custom events, shared stores, URL, or a pub/sub event bus.
Browser Custom Events
Use the browser's CustomEvent API as a simple event bus between micro-frontends without coupling them together.
// Remote emits:
window.dispatchEvent(new CustomEvent('cart:add', { detail: { productId: '123' } }));
// Host listens:
useEffect(() => {
const handler = (e: CustomEvent) => addToCart(e.detail.productId);
window.addEventListener('cart:add', handler);
return () => window.removeEventListener('cart:add', handler);
}, []);Shared Event Bus Library
A tiny pub/sub library shared (via Module Federation or a URL-loaded singleton) gives a typed event bus accessible to all MFEs.
// Singleton event bus
const bus = {
listeners: new Map<string, Function[]>(),
emit(event: string, data: unknown) {
this.listeners.get(event)?.forEach(fn => fn(data));
},
on(event: string, fn: Function) {
if (!this.listeners.has(event)) this.listeners.set(event, []);
this.listeners.get(event)!.push(fn);
return () => this.off(event, fn);
},
off(event: string, fn: Function) {
const list = this.listeners.get(event) || [];
this.listeners.set(event, list.filter(f => f !== fn));
},
};
export default bus;URL as Shared State
The URL (path + query params) is naturally shared between all MFEs. Use it for navigation state like selected item, active tab, or filter values.
// Remote reads from URL:
const params = new URLSearchParams(window.location.search);
const productId = params.get('product');
// Remote navigates via history API (or exposes a navigate callback from host):
window.history.pushState({}, '', '/products?product=456');Routing Architecture
Typically the shell/host app owns the top-level router. Remote micro-frontends receive the current path and a navigate callback as props.
// Host passes routing control to remote:
<RemoteProductsApp
basepath="/products"
navigate={(path) => router.push(path)}
/>
// Remote uses basepath for its internal router:
<BrowserRouter basename={basepath}>
<Routes>...</Routes>
</BrowserRouter>React Router with Module Federation
Each MFE can run its own React Router, scoped to its basepath. The host router handles top-level navigation; each remote handles sub-navigation independently.
// Remote App component:
export function ProductsApp({ basepath = '/products' }) {
return (
<BrowserRouter basename={basepath}>
<Routes>
<Route path="/" element={<ProductList />} />
<Route path="/:id" element={<ProductDetail />} />
</Routes>
</BrowserRouter>
);
}Shared Auth State
Auth state (user, token) is typically owned by the shell and passed down to remotes as props or exposed via a shared singleton store.
// Host provides auth via props:
<RemoteCheckout
userId={currentUser.id}
token={accessToken}
onLogout={handleLogout}
/>Zustand as Shared Store
When sharing a Zustand store via Module Federation (as a singleton), all MFEs read from the same store instance in memory.
// shared/store.ts (exposed as singleton)
import { create } from 'zustand';
export const useCartStore = create(set => ({
items: [],
addItem: (item) => set(state => ({ items: [...state.items, item] })),
}));
// Configured as singleton in MF shared configCross-MFE Communication Anti-Patterns
Avoid: deeply nested callback chains, sharing internal component state, or tight coupling to another MFE's internal APIs. Keep communication to coarse events and public contracts.
Testing Cross-MFE Interactions
Test the event contracts (event names, data shapes) separately from the UI. Use contract testing to verify that producer and consumer agree on the event schema.
Quick Check
What is the simplest way to share navigation/filter state between multiple micro-frontends without coupling them?
Recap
Share state between MFEs via custom events, a singleton event bus, the URL, or shared stores (Zustand/singleton). The shell owns the top-level router and passes basepath + navigate to remotes. Keep cross-MFE contracts coarse and well-typed.
Frequently asked questions
Is the “Shared State & Routing Between MFEs” lesson free?
Yes — the full text of “Shared State & Routing Between MFEs” is free to read here on the web, and the React Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the React Academy course, upgrade to CoddyKit PRO.
What will I learn in “Shared State & Routing Between MFEs”?
Share a global event bus or context across micro-frontends and coordinate client-side routing. You practise React Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start React Academy?
No prior experience is required. React Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Shared State & Routing Between MFEs” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this React Academy lesson?
Yes. Every React Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Micro-Frontend Concepts & Trade-offs
- Module Federation with Webpack 5
- Shared State & Routing Between MFEs
- Independent Deployment & CI Pipelines for MFEs