In server-side composition of microfrontends, such as using Server-Side Includes (SSI) or an edge-layer composition service, what actually happens between the browser's request and the fully assembled HTML response, and why does this approach tend to help SEO more than pure client-side JS mounting?
answer
- SSI include directive
- primary vs secondary fragment
- TTFB vs hydration
- fan-out timeout risk
- composition layer as single point of failure
basics
~20 sThe server (or a CDN edge) fetches each microfrontend's HTML piece and stitches them into one page before sending it to the browser, so the browser gets a complete, already-composed page instead of empty boxes that JavaScript fills in later.
solid answer
~40 sIn server-side composition, an edge or origin composition layer (classic SSI include directives, or a modern service like Zalando's open-source Tailor) receives the page request, fetches each contributing microfrontend's HTML fragment — often in parallel, sometimes streamed — from its own backend, and splices them into a single response body before it reaches the browser. Because the browser receives fully-formed HTML on the first response, search crawlers and users on slow connections see real content immediately without waiting for JS to hydrate, which is why this pattern is favored for SEO- and TTFB-sensitive pages versus client-side JS mounting, which ships mostly-empty HTML that only becomes content after bundles download and execute.
go deeper
Should know the basic shape — server assembles fragments into one HTML response before it reaches the browser — and that this helps because crawlers/slow devices see real content sooner.
Should name a concrete mechanism (SSI include directive or an edge composition service) and articulate the fan-out latency/single-point-of-failure trade-off against client-side JS mounting.
Should discuss streaming vs buffered composition, per-fragment timeout/fallback strategy, and how cache-control policy differs per fragment and must be reconciled.
Should reason about org-wide operational ownership — who's on call when the composition layer itself degrades, how fragment SLAs get negotiated across teams, and when to push personalization to a client-side layer on top of a cached, server-composed shell.
## What server-side composition is Server-side composition assembles a microfrontend page **before any HTML reaches the browser**, using either a very old, simple mechanism (Server-Side Includes, or SSI) or a modern, purpose-built edge/origin composition service (Zalando's open-source Tailor is the most commonly cited example). Both share the same core idea: the client makes one request for a page; something on the server side, not the browser, is responsible for - calling out to each contributing microfrontend's backend, - retrieving its rendered HTML fragment, - and stitching those fragments into a single HTML document that gets returned as the response body. ## SSI, the oldest form of this Mechanically, SSI is the oldest form of this: a web server (classically Apache with `mod_include`, or Nginx with its SSI module) scans an HTML template for directives like an include-virtual instruction, issues an internal or proxied HTTP request to that path, and substitutes the directive with the response body before serving the composed page. It requires no client-side JavaScript to produce initial content and **predates the microfrontend term by decades** — the same mechanism many large sites used to compose page furniture (headers, footers, navigation) from shared includes long before microfrontends was a phrase. ## The modern layout service Modern edge-composition services generalize this idea. A layout service such as Tailor: - defines a page template that names a **primary fragment** (which determines the HTTP status code and can influence caching) and any number of **secondary fragments**, - fetches all of them concurrently over HTTP, - and **streams** the composed response back to the browser — meaning fragments that resolve first start flowing to the browser immediately rather than waiting for the slowest fragment, which keeps Time-to-First-Byte low even under fan-out. ## Why the SEO and performance benefit follows The SEO and performance benefit follows directly from this mechanism: because the HTML the browser or crawler receives already contains the actual rendered content — product titles, prices, article text — there is no dependency on JavaScript execution for the page to be meaningful. - **Search engine crawlers** that render JS poorly, don't render it at all, or apply a rendering budget see complete content on the first pass. - **Users on slow networks or low-power devices** get visible, readable content as soon as the HTML streams in, well before any JS would have downloaded and hydrated in a client-composed equivalent. This is why server-side/edge composition is the default choice for public, SEO-critical surfaces like e-commerce category and product pages, versus client-side JS mounting which is more common for authenticated, app-like experiences where crawlability doesn't matter and interactivity/state-sharing matters more. ## The trade-offs run the other way The trade-offs run in the opposite direction from client-side composition. - **Fan-out latency** is now a first-class concern: the composed response can only be as fast as the slowest fragment's backend, unless the composition layer applies timeouts and fallback/placeholder content for slow fragments — a real production requirement, since a single microfrontend team's backend having a bad day can degrade or blank out part of everyone's page unless timeouts are enforced defensively. - **Fragment backends must all be reachable** from the server/edge network, which adds an operational dependency graph invisible to the browser — a composition-layer outage or misrouting takes down every page that depends on it, a single point of failure that pure client-side composition doesn't have, since there a failed microfrontend just fails to mount its widget, leaving the rest of the page intact. - **Caching also gets trickier**: each fragment may want a different cache policy (a promo banner cached for minutes, a personalized cart fragment never cached), and the composition layer has to reconcile per-fragment cache headers into one coherent response — get this wrong and you either serve stale personalized data or lose the caching benefit entirely. - **Client-side interactivity still has to be layered on top separately**, since each fragment typically ships its own small hydration script to attach event handlers to its already-rendered markup, so server-side composition doesn't eliminate client JS, it just decouples the initial render from it. ## A concrete failure mode A concrete failure mode: if the composition layer doesn't set an aggressive per-fragment timeout, one slow or hung fragment backend can pin a connection and worker on the composition service for the full request timeout, and under load this can exhaust the composition layer's connection pool, turning one team's backend blip into a site-wide outage — exactly the kind of blast-radius problem server-side composition is supposed to avoid at the browser layer but can reintroduce at the server layer if fragment calls aren't isolated with circuit breakers and fallbacks. This is why production implementations of this pattern pair the composition layer with: - strict per-fragment timeouts, - cached fallback fragments, - and monitoring on fragment latency specifically, not just overall page latency.
- How does Tailor's concept of a primary fragment affect what HTTP status code the browser sees?Tailor designates one fragment as primary and uses that fragment's own response status code as the status code for the whole composed page — so if the primary fragment's backend returns a 404, the composed page is served as a 404 even though other secondary fragments responded 200. This lets composition-layer behavior like error pages or redirects be driven by the fragment that actually owns the page's semantic meaning.
- What's the practical difference between streaming composition and buffered composition when one fragment is slow?Streaming composition starts flowing bytes for fragments that are already ready while still waiting on the slow one, so the browser can start rendering the top of the page immediately and the slow section fills in later. Buffered composition waits for every fragment to resolve before sending any bytes, so one slow fragment delays the entire response's Time-to-First-Byte, not just its own section.
- Why is per-fragment cache-control reconciliation harder than it looks in server-side composition?Different fragments legitimately need different freshness guarantees — a navigation fragment might be cacheable for hours while a personalized recommendations fragment must never be cached — but the composed response is a single HTTP response with one set of cache headers, so the composition layer has to either pick the most restrictive policy, losing caching benefit for the cacheable parts, or split personalization into a separate client-side call layered on top of the cached shell.
Server-side composition is like a restaurant expediter who collects each station's finished dish and plates the whole meal before it leaves the kitchen — the diner gets a complete plate immediately, but the meal can only go out as fast as the slowest station, and if the expediter's station jams, no plates leave at all.
saying these in an interview costs you the question
- Thinks server-side composition eliminates the need for any client-side JavaScript
- Doesn't know SSI predates the microfrontend pattern and is a real server directive, not just a buzzword
- Assumes all fragments must fully resolve before any bytes are sent, missing streaming
- Can't explain why a slow fragment backend is dangerous without timeouts
- Conflates server-side composition with server-side rendering of a single monolithic app