0Pricing
Vue Academy · Lesson

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 slices

Updating 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 + addEventListener gives framework-agnostic messaging; clean up in onUnmounted.
  • 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: true in 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

  1. Micro-Frontend Architecture Principles
  2. Webpack Module Federation with Vue
  3. Vite Federation Plugin
  4. Shared State Across Micro-Frontends
← Back to Vue Academy