Svelte • Runtime

Hydratable data

On this page

In Svelte, when you want to render asynchronous content data on the server, you can simply await it. This is great! However, it comes with a pitfall: when hydrating that content on the client, Svelte has to redo the asynchronous work, which blocks hydration for however long it takes:

<script lang="ts">
  import { getUser } from 'my-database-library';

  // This will get the user on the server, render the user's name into the h1,
  // and then, during hydration on the client, it will get the user _again_,
  // blocking hydration until it's done.
  const user = await getUser();
</script>

<h1>{user.name}</h1>
<script>
  import { getUser } from 'my-database-library';

  // This will get the user on the server, render the user's name into the h1,
  // and then, during hydration on the client, it will get the user _again_,
  // blocking hydration until it's done.
  const user = await getUser();
</script>

<h1>{user.name}</h1>

That’s silly, though. If we’ve already done the hard work of getting the data on the server, we don’t want to get it again during hydration on the client. hydratable is a low-level API built to solve this problem. You probably won’t need this very often — it will be used behind the scenes by whatever datafetching library you use. For example, it powers remote functions in SvelteKit.

To fix the example above:

<script lang="ts">
  import { hydratable } from 'svelte';
  import { getUser } from 'my-database-library';

  // During server rendering, this will serialize and stash the result of `getUser`, associating
  // it with the provided key and baking it into the `head` content. During hydration, it will
  // look for the serialized version, returning it instead of running `getUser`. After hydration
  // is done, if it's called again, it'll simply invoke `getUser`.
  const user = await hydratable('user', () => getUser());
</script>

<h1>{user.name}</h1>
<script>
  import { hydratable } from 'svelte';
  import { getUser } from 'my-database-library';

  // During server rendering, this will serialize and stash the result of `getUser`, associating
  // it with the provided key and baking it into the `head` content. During hydration, it will
  // look for the serialized version, returning it instead of running `getUser`. After hydration
  // is done, if it's called again, it'll simply invoke `getUser`.
  const user = await hydratable('user', () => getUser());
</script>

<h1>{user.name}</h1>

This API can also be used to provide access to random or time-based values that are stable between server rendering and hydration. For example, to get a random number that doesn’t update on hydration:

import { function hydratable<T>(key: string, fn: () => T): Tfunction hydratable<T>(key: string, fn: () => T): Thydratable } from 'svelte';
const const rand: numberconst rand: numberrand = hydratable<number>(key: string, fn: () => number): numberhydratable<number>(key: string, fn: () => number): numberhydratable('random', () => var Math: Math

An intrinsic object that provides basic mathematics functionality and constants.

var Math: Math

An intrinsic object that provides basic mathematics functionality and constants.

Math
.Math.random(): number

Returns a pseudorandom number between 0 and 1.

Math.random(): number

Returns a pseudorandom number between 0 and 1.

random
());

If you’re a library author, be sure to prefix the keys of your hydratable values with the name of your library so that your keys don’t conflict with other libraries.

Serialization

All data returned from a hydratable function must be serializable. But this doesn’t mean you’re limited to JSON — Svelte uses devalue, which can serialize all sorts of things including Map, Set, URL, and BigInt. Check the documentation page for a full list. In addition to these, thanks to some Svelte magic, you can also fearlessly use promises:

<script lang="ts">
  import { function hydratable<T>(key: string, fn: () => T): Thydratable } from 'svelte';
  const 
const promises: {
    one: Promise<number>;
    two: Promise<number>;
}
promises
=
hydratable<{
    one: Promise<number>;
    two: Promise<number>;
}>(key: string, fn: () => {
    one: Promise<number>;
    two: Promise<number>;
}): {
    one: Promise<number>;
    two: Promise<number>;
}
hydratable
('random', () => {
return { one: Promise<number>one: var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.PromiseConstructor.resolve<number>(value: number): Promise<number> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.@returnsA promise whose internal state matches the provided promise.
resolve
(1),
two: Promise<number>two: var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.PromiseConstructor.resolve<number>(value: number): Promise<number> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.@returnsA promise whose internal state matches the provided promise.
resolve
(2)
} }); </script> {await
const promises: {
    one: Promise<number>;
    two: Promise<number>;
}
promises
.one: Promise<number>one}
{await
const promises: {
    one: Promise<number>;
    two: Promise<number>;
}
promises
.two: Promise<number>two}
<script>
  import { function hydratable<T>(key: string, fn: () => T): Thydratable } from 'svelte';
  const 
const promises: {
    one: Promise<number>;
    two: Promise<number>;
}
promises
=
hydratable<{
    one: Promise<number>;
    two: Promise<number>;
}>(key: string, fn: () => {
    one: Promise<number>;
    two: Promise<number>;
}): {
    one: Promise<number>;
    two: Promise<number>;
}
hydratable
('random', () => {
return { one: Promise<number>one: var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.PromiseConstructor.resolve<number>(value: number): Promise<number> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.@returnsA promise whose internal state matches the provided promise.
resolve
(1),
two: Promise<number>two: var Promise: PromiseConstructor

Represents the completion of an asynchronous operation

Promise
.PromiseConstructor.resolve<number>(value: number): Promise<number> (+2 overloads)

Creates a new resolved promise for the provided value.

@paramvalue A promise.@returnsA promise whose internal state matches the provided promise.
resolve
(2)
} }); </script> {await
const promises: {
    one: Promise<number>;
    two: Promise<number>;
}
promises
.one: Promise<number>one}
{await
const promises: {
    one: Promise<number>;
    two: Promise<number>;
}
promises
.two: Promise<number>two}

CSP

hydratable adds an inline <script> block to the head returned from render. If you’re using Content Security Policy (CSP), this script will likely fail to run. You can provide a nonce to render:

import { 
function render<Comp extends SvelteComponent<any> | Component<any>, Props extends ComponentProps<Comp> = ComponentProps<Comp>>(...args: {} extends Props ? [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options?: {
    props?: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: (error: unknown) => unknown | Promise<unknown>;
}] : [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options: {
    props: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: (error: unknown) => unknown | Promise<unknown>;
}]): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

function render<Comp extends SvelteComponent<any> | Component<any>, Props extends ComponentProps<Comp> = ComponentProps<Comp>>(...args: {} extends Props ? [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options?: {
    props?: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: (error: unknown) => unknown | Promise<unknown>;
}] : [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options: {
    props: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: (error: unknown) => unknown | Promise<unknown>;
}]): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render
} from 'svelte/server';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte';
// cut const const nonce: `${string}-${string}-${string}-${string}-${string}`const nonce: `${string}-${string}-${string}-${string}-${string}`nonce = var crypto: Cryptovar crypto: Cryptocrypto.Crypto.randomUUID(): `${string}-${string}-${string}-${string}-${string}`

The randomUUID() method of the Crypto interface is used to generate a v4 UUID using a cryptographically secure random number generator. Available only in secure contexts.

MDN Reference

Crypto.randomUUID(): `${string}-${string}-${string}-${string}-${string}`

The randomUUID() method of the Crypto interface is used to generate a v4 UUID using a cryptographically secure random number generator. Available only in secure contexts.

MDN Reference

randomUUID
();
const { const head: string

HTML that goes into the <head>

const head: string

HTML that goes into the <head>

head
, const body: string

HTML that goes somewhere into the <body>

const body: string

HTML that goes somewhere into the <body>

body
} = await
render<SvelteComponent<Record<string, any>, any, any>, Record<string, any>>(component: ComponentType<SvelteComponent<Record<string, any>, any, any>>, options?: {
    props?: Omit<Record<string, any>, "$$slots" | "$$events"> | undefined;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: ((error: unknown) => unknown | Promise<unknown>) | undefined;
} | undefined): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render<SvelteComponent<Record<string, any>, any, any>, Record<string, any>>(component: ComponentType<SvelteComponent<Record<string, any>, any, any>>, options?: {
    props?: Omit<Record<string, any>, "$$slots" | "$$events"> | undefined;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: ((error: unknown) => unknown | Promise<unknown>) | undefined;
} | undefined): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render
(const App: LegacyComponentTypeconst App: LegacyComponentTypeApp, {
csp?: Csp | undefinedcsp?: Csp | undefinedcsp: { nonce?: string | undefinednonce?: string | undefinednonce } });

This will add the nonce to the script block, on the assumption that you will later add the same nonce to the CSP header of the document that contains it:

let let response: Responselet response: Responseresponse = new var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response

The Response interface of the Fetch API represents the response to a request.

MDN Reference

var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response

The Response interface of the Fetch API represents the response to a request.

MDN Reference

Response
();
let let nonce: stringlet nonce: stringnonce = 'xyz123'; // cut let response: Responselet response: Responseresponse.Response.headers: Headers

The headers read-only property of the Response interface contains the Headers object associated with the response.

MDN Reference

Response.headers: Headers

The headers read-only property of the Response interface contains the Headers object associated with the response.

MDN Reference

headers
.Headers.set(name: string, value: string): void

The set() method of the Headers interface sets a new value for an existing header inside a Headers object, or adds the header if it does not already exist.

MDN Reference

Headers.set(name: string, value: string): void

The set() method of the Headers interface sets a new value for an existing header inside a Headers object, or adds the header if it does not already exist.

MDN Reference

set
(
'Content-Security-Policy', `script-src 'nonce-${let nonce: stringlet nonce: stringnonce}'` );

It’s essential that a nonce — which, British slang definition aside, means ‘number used once’ — is only used when dynamically server rendering an individual response.

If instead you are generating static HTML ahead of time, you must use hashes instead:

import { 
function render<Comp extends SvelteComponent<any> | Component<any>, Props extends ComponentProps<Comp> = ComponentProps<Comp>>(...args: {} extends Props ? [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options?: {
    props?: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: (error: unknown) => unknown | Promise<unknown>;
}] : [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options: {
    props: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: (error: unknown) => unknown | Promise<unknown>;
}]): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

function render<Comp extends SvelteComponent<any> | Component<any>, Props extends ComponentProps<Comp> = ComponentProps<Comp>>(...args: {} extends Props ? [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options?: {
    props?: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: (error: unknown) => unknown | Promise<unknown>;
}] : [component: Comp extends SvelteComponent<any> ? ComponentType<Comp> : Comp, options: {
    props: Omit<Props, "$$slots" | "$$events">;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: (error: unknown) => unknown | Promise<unknown>;
}]): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render
} from 'svelte/server';
import
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
type App = SvelteComponent<Record<string, any>, any, any>
const App: LegacyComponentType
App
from './App.svelte';
// cut const { const head: string

HTML that goes into the <head>

const head: string

HTML that goes into the <head>

head
, const body: string

HTML that goes somewhere into the <body>

const body: string

HTML that goes somewhere into the <body>

body
,
const hashes: {
    script: `sha256-${string}`[];
}
const hashes: {
    script: `sha256-${string}`[];
}
hashes
} = await
render<SvelteComponent<Record<string, any>, any, any>, Record<string, any>>(component: ComponentType<SvelteComponent<Record<string, any>, any, any>>, options?: {
    props?: Omit<Record<string, any>, "$$slots" | "$$events"> | undefined;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: ((error: unknown) => unknown | Promise<unknown>) | undefined;
} | undefined): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render<SvelteComponent<Record<string, any>, any, any>, Record<string, any>>(component: ComponentType<SvelteComponent<Record<string, any>, any, any>>, options?: {
    props?: Omit<Record<string, any>, "$$slots" | "$$events"> | undefined;
    context?: Map<any, any>;
    idPrefix?: string;
    csp?: Csp;
    transformError?: ((error: unknown) => unknown | Promise<unknown>) | undefined;
} | undefined): RenderOutput

Only available on the server and when compiling with the server option. Takes a component and returns an object with body and head properties on it, which you can use to populate the HTML when server-rendering your app.

render
(const App: LegacyComponentTypeconst App: LegacyComponentTypeApp, {
csp?: Csp | undefinedcsp?: Csp | undefinedcsp: { hash?: boolean | undefinedhash?: boolean | undefinedhash: true } });

hashes.script will be an array of strings like ["sha256-abcd123"]. As with nonce, the hashes should be used in your CSP header:

let let response: Responselet response: Responseresponse = new var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response

The Response interface of the Fetch API represents the response to a request.

MDN Reference

var Response: new (body?: BodyInit | null, init?: ResponseInit) => Response

The Response interface of the Fetch API represents the response to a request.

MDN Reference

Response
();
let
let hashes: {
    script: string[];
}
let hashes: {
    script: string[];
}
hashes
= { script: string[]script: string[]script: ['sha256-xyz123'] };
// cut let response: Responselet response: Responseresponse.Response.headers: Headers

The headers read-only property of the Response interface contains the Headers object associated with the response.

MDN Reference

Response.headers: Headers

The headers read-only property of the Response interface contains the Headers object associated with the response.

MDN Reference

headers
.Headers.set(name: string, value: string): void

The set() method of the Headers interface sets a new value for an existing header inside a Headers object, or adds the header if it does not already exist.

MDN Reference

Headers.set(name: string, value: string): void

The set() method of the Headers interface sets a new value for an existing header inside a Headers object, or adds the header if it does not already exist.

MDN Reference

set
(
'Content-Security-Policy', `script-src ${
let hashes: {
    script: string[];
}
let hashes: {
    script: string[];
}
hashes
.script: string[]script: string[]script.Array<string>.map<string>(callbackfn: (value: string, index: number, array: string[]) => string, thisArg?: any): string[]

Calls a defined callback function on each element of an array, and returns an array that contains the results.

@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
Array<string>.map<string>(callbackfn: (value: string, index: number, array: string[]) => string, thisArg?: any): string[]

Calls a defined callback function on each element of an array, and returns an array that contains the results.

@paramcallbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array.@paramthisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
map
((hash: stringhash: stringhash) => `'${hash: stringhash: stringhash}'`).Array<string>.join(separator?: string): string

Adds all the elements of an array into a string, separated by the specified separator string.

@paramseparator A string used to separate one element of the array from the next in the resulting string. If omitted, the array elements are separated with a comma.
Array<string>.join(separator?: string): string

Adds all the elements of an array into a string, separated by the specified separator string.

@paramseparator A string used to separate one element of the array from the next in the resulting string. If omitted, the array elements are separated with a comma.
join
(' ')}`
);

We recommend using nonce over hash if you can, as hash will interfere with streaming SSR in the future.