Run-time Integration & Deploy
This is where micro-frontends earn their name: each slice is independently deployed, living at its own URL on its own pipeline, and the Astro shell stitches them together at run time. No shell rebuild is needed when a team ships — the shell simply loads whatever is currently live. Here are the four main techniques, from softest to hardest isolation.
Web Components — framework-agnostic custom elements
Section titled “Web Components — framework-agnostic custom elements”A team can compile its slice into a custom element and publish a single script. The shell loads that script and uses the element like any HTML tag — no framework lock-in, because the browser owns the element registry:
---// The shell loads a team's element bundle.---<script src="https://cart.acme.dev/cart-widget.js" type="module"></script><cart-widget user-id="42"></cart-widget>Web Components are the most natural run-time boundary in Astro: they are just HTML, they encapsulate their own styles via shadow DOM, and any framework (Lit, Stencil, Svelte, even React via a wrapper) can emit them.
iframes — the hardest isolation
Section titled “iframes — the hardest isolation”When a slice must be completely sealed off — third-party code, a legacy app, strict security boundaries — an iframe gives you a separate document, separate CSS, and separate JavaScript globals:
<iframe src="https://legacy.acme.dev/reviews" title="Reviews"></iframe>The isolation is total, which is also the downside: communication is limited to postMessage, sizing is awkward, and you pay for a second document. Reach for iframes only when you truly need that wall.
Remote fragments — fetch and inline on the server
Section titled “Remote fragments — fetch and inline on the server”The Astro shell can fetch a team’s rendered HTML on the server — in a server island or an endpoint — and inline it into the page. This keeps the client lean: the user receives one HTML document, already composed.
---// Server-side: fetch a team's rendered fragment.const res = await fetch('https://reviews.acme.dev/fragment');const html = await res.text();---<section set:html={html}></section>You can also expose this from an Astro endpoint (src/pages/api/reviews.ts) so other shells reuse it. Pair it with server:defer (from the previous lesson) so a slow fragment never blocks the page.
Module Federation via Vite
Section titled “Module Federation via Vite”Module Federation lets one app consume modules from another at run time, fetched over the network. Because Astro builds on Vite, you can use the @module-federation/vite plugin to expose modules from team apps and consume them in the shell:
npm install @module-federation/viteThis is the most “SPA-native” run-time option — teams expose components that the shell imports dynamically without bundling them in. It is powerful but the heaviest to operate: shared-dependency versioning (so React is not loaded twice) and build-config coordination become real work.
Stitching it together
Section titled “Stitching it together”flowchart TD
subgraph Teams["Independently deployed MFEs"]
A["cart.acme.dev\n(Web Component)"]
B["reviews.acme.dev\n(remote fragment)"]
C["catalog.acme.dev\n(federated module)"]
D["legacy.acme.dev\n(iframe)"]
end
Shell["Astro shell — composes at run time"]
A --> Shell
B --> Shell
C --> Shell
D --> Shell
Shell --> Page["One stitched page"] Cross-MFE communication and shared routing
Section titled “Cross-MFE communication and shared routing”Independent slices still sometimes need to talk — “item added to cart” must reach the cart badge. Keep the contract small and decoupled:
- Custom events on the
window: one slice doeswindow.dispatchEvent(new CustomEvent('cart:add', { detail }))and another listens. No shared bundle required. - A tiny shared store like nanostores: a single small atom both slices import to read and write shared state reactively, framework-agnostic and a few hundred bytes.
For shared routing, let the Astro shell own the URL and the layout. Each slice handles its own internal view state but defers top-level navigation to the shell, so the back button and deep links behave consistently across teams.
Independent deployment, versioning and pitfalls
Section titled “Independent deployment, versioning and pitfalls”Independent deploys are the prize and the hazard. A few rules keep it sane:
- Version your contracts, not just your code. The props an element accepts, the event names, the fragment’s HTML shape — treat these as a public API and version them.
- Pin or negotiate shared dependencies. Without care, three slices ship three copies of React. Module Federation’s shared config, or simply standardizing on Astro islands, avoids the duplication tax.
- Guard consistency. Design tokens, fonts, and accessibility must be enforced across repos (a shared CSS/token package), or the page drifts into looking like four different products.
- Fail gracefully. A run-time slice can be down. Wrap remote fetches and federated imports so one dead team degrades to a fallback instead of a blank page.
Run-time integration is what makes the org chart visible in the architecture: every team owns a URL, ships when it wants, and the Astro shell — static, fast, framework-agnostic — quietly composes them into one page.