vuejs/core
Server-side rendering
Vue's SSR splits across three packages:
@vue/compiler-ssrgenerates SSR-flavored render functions that push string fragments instead of vnodes. See packages/compiler-ssr.@vue/server-rendererdrives those render functions, manages the SSR context, and exposes string + stream APIs. See packages/server-renderer.@vue/runtime-coreis reused for component instance creation, props/slots normalization, async dependency tracking, and built-in component logic. The internalssrUtilsexport (gated by__SSR__) is the curated entry point for the server renderer.
This page describes how a render goes from renderToString(app) to a finished HTML string.
The SSR render
sequenceDiagram
participant Caller as renderToString(app)
participant SR as server-renderer
participant RC as runtime-core ssrUtils
participant Comp as ComponentInternalInstance
participant SSRFn as ssrRender (generated)
Caller->>SR: renderToString(app)
SR->>SR: createApp().mount('<placeholder>') in SSR mode
SR->>RC: createComponentInstance + setupComponent
RC->>Comp: run setup() (may await)
SR->>Comp: pull instance.ssrRender
SR->>SSRFn: ssrRender(_ctx, _push, _parent, _attrs)
SSRFn->>SR: _push("<div ...>") and recurse
SR-->>Caller: resolved stringThe renderer's primary loop is in packages/server-renderer/src/render.ts. For each component:
createComponentInstance(vnode, parent, suspense)is called viassrUtils.createComponentInstance.setupComponent(instance, /* isSSR */ true)runssetup()and applies Options API normalization. Ifsetup()is async (returns a Promise or uses top-level await), the renderer awaits before continuing.- The component's
ssrRender(precompiled by@vue/compiler-ssr) is invoked with(ctx, _push, _parent, _attrs)._pushwrites string chunks to the active buffer.
If a component lacks a precompiled ssrRender (e.g., it has only a runtime render), the server renderer falls back to invoking render to get a vnode tree, then walks the vnodes with the same SSR helpers. This is slower but keeps semantics consistent.
What compiler-ssr emits
A simple template:
<template>
<div :class="cls">{{ msg }}</div>
</template>Compiles (via @vue/compiler-ssr.compile with mode: 'module') to roughly:
import { ssrInterpolate, ssrRenderClass } from '@vue/server-renderer';
export function ssrRender(_ctx, _push, _parent, _attrs) {
_push(
`<div class="${ssrRenderClass(_ctx.cls)}">${ssrInterpolate(_ctx.msg)}</div>`
);
}Calls to ssrRenderAttrs, ssrRenderClass, ssrRenderStyle, ssrInterpolate, ssrRenderComponent, ssrRenderSlot, ssrRenderTeleport, ssrRenderSuspense, etc., are all defined in packages/server-renderer/src/helpers/. The names listed in packages/compiler-ssr/src/runtimeHelpers.ts must match these exports — that's how the compiler/runtime stay in sync.
SSR context
The user passes (or the server renderer creates) an SSRContext object. It carries:
_teleports— a record oftarget-selector → rendered-stringpopulated byssrRenderTeleport. The server caller can splice these into the right places in the final HTML envelope.- Module assignments from
<script>modules. - CSS variables collected by
useCssVars.
useSSRContext() (re-exported from runtime-core) is how a component reads the context.
Streams
renderToString buffers the full output before resolving. For large pages, the stream variants in packages/server-renderer/src/renderToStream.ts produce content incrementally:
renderToSimpleStream(input, ctx, stream)— lowest-level. Accepts aSimpleReadable({ push(chunk), destroy(reason?) }).renderToNodeStream(input, ctx?)— Node-styleReadableadapter.pipeToNodeWritable(input, ctx, writable)— pumps chunks into aWritable.renderToWebStream(input, ctx?)— WebReadableStreamadapter.pipeToWebWritable(input, ctx, writable)— WebWritableStreamadapter.
Internally, all variants share a buffer model where each component appends a Buffer (a recursive list of strings or Promise<script setup>, <Suspense> async children) become Promise
Async components and Suspense
defineAsyncComponent returns a wrapper that resolves to the real component on first use. In SSR:
- The wrapper's pending promise is awaited before its render runs.
<Suspense>collects pending dependencies of its default slot. If any are still pending after atimeout(or the suspense itself resolves synchronously), the fallback slot is rendered instead.
packages/server-renderer/src/helpers/ssrRenderSuspense.ts is the SSR-side handler. packages/runtime-core/src/components/Suspense.ts provides the boundary type that the SSR code consults.
Hydration mismatch
The expected client-side hydration consumes the SSR-produced markup verbatim. Mismatches surface in dev as warnings via packages/runtime-core/src/hydration.ts. Common sources of mismatches:
- Markup that depends on
Date.now()orMath.random()(different on each side). - Branches gated by
typeof window. - Interpolating user-provided HTML differently in SSR vs client.
- Whitespace differences when
whitespace: 'preserve'is not aligned across compile passes.
The flag __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ enables detailed mismatch reports in production builds at the cost of bundle size.
Directives in SSR
v-show and v-model need SSR-aware behavior so the server-rendered markup matches what the client will hydrate. runtime-dom/src/index.ts exports initDirectivesForSSR; server-renderer/src/index.ts calls it on import. The actual SSR transforms live in packages/compiler-ssr/src/transforms/ssrVModel.ts and ssrVShow.ts, but the runtime initializers in runtime-dom/src/directives/vModel.ts and vShow.ts provide the matching getSSRProps hook the SSR pipeline calls.
Files to know
packages/server-renderer/src/render.tspackages/server-renderer/src/renderToString.tspackages/server-renderer/src/renderToStream.tspackages/server-renderer/src/helpers/ssrRenderAttrs.tspackages/server-renderer/src/helpers/ssrRenderComponent.tspackages/server-renderer/src/helpers/ssrRenderTeleport.tspackages/server-renderer/src/helpers/ssrRenderSuspense.tspackages/compiler-ssr/src/index.tspackages/compiler-ssr/src/transforms/ssrTransformElement.tspackages/compiler-ssr/src/transforms/ssrTransformComponent.tspackages/runtime-core/src/index.ts(look forssrUtils)packages/runtime-core/src/components/Suspense.ts
Companion: hydration
For the client-side counterpart of SSR — taking the produced markup and binding it to the live component tree — see hydration.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.