TanStack
Guides

SSR and Hydration

TanStack Charts builds a platform-neutral scene before the selected renderer produces output. React, Preact, Vue, Solid, Svelte, and Octane use the same runtime and renderer on the server and in the browser.

Adapter support

AdapterServer outputBrowser contract
ReactComplete SVG; Canvas shellHydrates and adopts the existing surface
PreactComplete SVGHydrates before the shared host mounts
VueComplete SVGHydrates before the shared host mounts
SolidComplete SVGHydrates before the shared host mounts
SvelteComplete SVGHydrates before the shared host mounts
OctaneComplete SVG; Canvas shellHydrates and adopts the existing surface
AngularNot yet a verified adapter contractBrowser mount, immutable update, and teardown
LitNot yet a verified adapter contractBrowser registration, update, disconnect, reconnect
AlpineNoneBrowser-only directive

For adapters with server output, the browser must render the same definition, input, dimensions, formatters, and component tree. Angular and Lit may run inside applications with their own server infrastructure, but this library does not yet promise or test adapter hydration for them.

Give the server a real size

The server cannot measure a container. Supply one of these policies:

  • width and height for a fixed-size chart;
  • width and aspectRatio for a fixed-width proportional chart;
  • initialWidth and height for a responsive chart;
  • initialWidth and aspectRatio when height should follow width.
tsx
<Chart
  definition={trafficChart}
  ariaLabel="Daily traffic"
  initialWidth={720}
  aspectRatio={16 / 9}
/>

The adapter uses an explicit width before initialWidth when deriving the server height. After mounting, a responsive host observes the container and renders at its measured width. Pick an initialWidth close to the layout's common size to minimize the first responsive adjustment.

See Responsive Charts for the complete size policy.

Keep output deterministic

Server and first-client output must agree for the same definition, input, size, and options. In particular:

  • create definitions at module scope;
  • sort unordered collections before creating marks;
  • do not read window, layout, time, locale, or random values while building a definition;
  • pass locale-sensitive formatters explicitly;
  • use stable keys derived from data identity;
  • provide idPrefix when multiple render roots need coordinated resource IDs.

Dynamic chart functions are synchronous. Fetch and transform data in the application's server/data layer, then pass the resolved input to the chart.

Hydration ownership

Server and browser executions create separate runtime instances. Within the browser adapter's own initial render and layout-effect mount, the DOM host receives the already created browser runtime.

Do not conditionally replace a chart with a different component only because the code is executing on the server. That creates a different tree and gives up the shared render path.

Canvas server shell

@tanstack/react-charts/canvas and @tanstack/octane-charts/canvas render a deterministic accessible shell on the server: a named chart root and two aria-hidden canvas elements with the initial scene dimensions. No server Canvas API or pixel painting is required.

The client renders the same shell, adopts its existing root and canvases, sizes their backing stores for the device-pixel ratio, paints the scene, and attaches the shared interaction host. The first image appears after client mount; use the default SVG adapter when visible server-rendered geometry is required.

Fonts and text measurement

Automatic guide margins depend on text metrics. The server uses deterministic fallback measurement unless you provide measureText. The browser host remeasures when fonts become available and schedules a new layout.

For strict pixel parity:

  1. Use a font available in both environments.
  2. Supply a deterministic ChartTextMeasurer.
  3. Keep font size and weight in chart configuration rather than ambient, late-changing CSS.

Most applications should allow the browser's post-font layout correction instead of shipping a font engine to the server.

Render without a framework

createChartRuntime and renderChartSvg form the server boundary:

ts
import { createChartRuntime, renderChartSvg } from '@tanstack/charts'

const runtime = createChartRuntime<TrafficRow, TrafficInput, Date, number>()
const scene = runtime.render(definition, input, { width: 720, height: 400 })

const svg = renderChartSvg(scene, {
  ariaLabel: 'Daily traffic',
  idPrefix: 'traffic',
})

runtime.destroy()

renderChartSvg returns a string and does not require a DOM. A custom ChartRenderer.prerender may produce another deterministic shell. Browser-only focus, tooltip, reconciliation or paint, animation, and export begin when its surface mounts.

Hydration checklist

  • Server input is fully resolved before chart rendering.
  • Initial dimensions are explicit and representative.
  • Definition, transformed input, and formatting are deterministic.
  • Keys and idPrefix are stable.
  • The same adapter and definition render on both sides.
  • Browser-only work lives in host callbacks or application effects.
  • Font-driven relayout is expected or a text measurer is supplied.

See the selected framework adapter page and Runtime and Scene for the exact contracts.