Shared State Across Micro-Frontends
Sharing Pinia stores, event bus via CustomEvent, URL as shared state.
Shared State Across Micro-Frontends is a free Vue Academy lesson on CoddyKit — lesson 4 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 Vue Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Shared State Challenge
Independent micro-frontends still need to coordinate: a login in one slice should update the header in another. But tight coupling defeats the point. The goal is loose, deliberate communication.
Avoid Implicit Global State
Dumping everything on window or a giant shared store recreates the monolith’s coupling. Prefer explicit, minimal contracts between slices so teams can evolve independently.
CustomEvent for Communication
The browser’s CustomEvent API is a framework-agnostic bus. One micro-frontend dispatches an event on window; others listen — no shared imports required.
const event = new CustomEvent("cart:add", {
detail: { productId: 42, qty: 1 },
})
window.dispatchEvent(event)Listening for Events
Other slices subscribe with addEventListener and read the payload from event.detail. This decouples sender and receiver — they only agree on an event name and shape.
window.addEventListener("cart:add", (e) => {
console.log("Added", e.detail.productId)
})Cleaning Up Listeners in Vue
Register listeners in onMounted and remove them in onUnmounted to avoid leaks and duplicate handlers when components remount.
import { onMounted, onUnmounted } from "vue"
function onAdd(e) { /* ... */ }
onMounted(() => window.addEventListener("cart:add", onAdd))
onUnmounted(() => window.removeEventListener("cart:add", onAdd))A Typed Event Contract
Document the events as a contract so every team knows the name and payload shape. This is the public API between micro-frontends.
// events contract
// "cart:add" -> { productId: number, qty: number }
// "auth:login" -> { userId: string }
// "auth:logout" -> {}URL as Shared State
The URL is a natural shared store for navigation and filters: it is global, bookmarkable, and every slice can read it. Put cross-cutting state like the active filter or page in query params.
const params = new URLSearchParams(location.search)
const category = params.get("category") // shared across slicesUpdating URL State
Write shared filter/navigation state to the URL with the History API so it stays shareable and back-button friendly. All slices react by reading the new URL.
function setCategory(value) {
const url = new URL(location.href)
url.searchParams.set("category", value)
history.pushState({}, "", url)
}Singleton Pinia Store
For richer shared state within a single page, a singleton Pinia store works — but only if Pinia is shared as a singleton across federation so all slices use the same instance.
// federation config (both sides)
shared: {
pinia: { singleton: true },
vue: { singleton: true },
}Using the Shared Store
With Pinia shared as a singleton, a store imported by two slices is the same store instance — state written by one is read by the other reactively.
// slice A writes
const auth = useAuthStore()
auth.login(user)
// slice B reads the same reactive state
const auth = useAuthStore()
console.log(auth.user)Choosing a Strategy
- CustomEvent — loose, framework-agnostic notifications.
- URL — navigation, filters, anything shareable/bookmarkable.
- Singleton Pinia — rich in-page reactive state, requires
singleton: true.
Favor the loosest option that meets the need.
Quick Check
Check your understanding of cross-MFE state.
Recap
You learned to share state across micro-frontends:
- Prefer loose, explicit contracts over implicit global state.
- CustomEvent on
window+addEventListenergives framework-agnostic messaging; clean up inonUnmounted. - The URL (query params via the History API) holds shareable navigation and filter state.
- A singleton Pinia store shares rich reactive state, but only with
singleton: truein federation.
Frequently asked questions
Is the “Shared State Across Micro-Frontends” lesson free?
Yes — the full text of “Shared State Across Micro-Frontends” is free to read here on the web, and the Vue 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 Vue Academy course, upgrade to CoddyKit PRO.
What will I learn in “Shared State Across Micro-Frontends”?
Sharing Pinia stores, event bus via CustomEvent, URL as shared state. You practise Vue 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 Vue Academy?
No prior experience is required. Vue Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Shared State Across Micro-Frontends” 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 Vue Academy lesson?
Yes. Every Vue 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 Architecture Principles
- Webpack Module Federation with Vue
- Vite Federation Plugin
- Shared State Across Micro-Frontends