resumeAndPrerender Web Streams API (experimental)
resumeAndPrerender continues a prerendered React tree to static HTML with a Readable Web Stream. It is an experimental API available in environments with Web Streams support, including browsers, Deno, and some modern edge runtimes.
Node.js Stream APIs in react-dom/static
Node.js includes prerender and resumeAndPrerender methods for compatibility with Web Streams, but they are not recommended due to worse performance. Use the dedicated Node.js APIs (prerenderToNodeStream and resumeAndPrerenderToNodeStream) instead.
prerenderToNodeStream API
prerenderToNodeStream renders a React tree to static HTML with a Node.js Stream. It is available in environments with Node.js Streams support.
resumeAndPrerenderToNodeStream API (experimental)
resumeAndPrerenderToNodeStream continues a prerendered React tree to static HTML with a Node.js Stream. It is an experimental API available in environments with Node.js Streams support.
react-dom/static APIs overview
The react-dom/static APIs let you generate static HTML for React components. They have limited functionality compared to the streaming APIs. A framework may call them for you. Most components do not need to import or use them directly.
prerender Web Streams API
prerender renders a React tree to static HTML with a Readable Web Stream. It is available in environments with Web Streams support, including browsers, Deno, and some modern edge runtimes.
resumeAndPrerender relationship to prerender
resumeAndPrerender behaves similarly to prerender but can be used to continue a previously started prerendering process that was aborted.
resumeAndPrerender Web Stream requirement
resumeAndPrerender depends on Web Streams API. For Node.js, use resumeAndPrerenderToNodeStream instead.
resumeAndPrerender nonce caveat
nonce is not an available option when using resumeAndPrerender. Nonces must be unique per request and it would be inappropriate and insecure to include the nonce value in the prerender itself when using CSP.
resumeAndPrerender use case
resumeAndPrerender is used for static server-side generation (SSG). Unlike renderToString, resumeAndPrerender waits for all data to load before resolving, making it suitable for generating static HTML for a full page including data fetched using Suspense. resumeAndPrerender can be aborted and later either continued with another resumeAndPrerender or resumed with resume to support partial pre-rendering.
resumeAndPrerender example
import { resumeAndPrerender } from 'react-dom/static';
import { getPostponedState } from 'storage';
async function handler(request, response) {
const postponedState = getPostponedState(request);
const { prelude } = await resumeAndPrerender(<App />, postponedState, {
bootstrapScripts: ['/main.js']
});
return new Response(prelude, {
headers: { 'content-type': 'text/html' },
});
}
This example shows resumeAndPrerender continuing a prerendered React tree and returning the HTML stream in a response.
resumeAndPrerender client hydration
On the client, call hydrateRoot to make the server-generated HTML from resumeAndPrerender interactive.
resumeAndPrerender return value
resumeAndPrerender returns a Promise that resolves to an object containing prelude (a Web Stream of HTML) and postponed (a JSON-serializable opaque object that can be passed to resume or resumeAndPrerender if prerender is aborted). If rendering fails, the Promise is rejected.
resumeAndPrerender import path
resumeAndPrerender is imported from 'react-dom/static'.
Passing assetMap to client via bootstrapScriptContent
Pass the assetMap to the client by serializing it in a bootstrap script:
```js
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
};
app.use('/', async (request, response) => {
const { prelude } = await prerenderToNodeStream(<App />, {
bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`,
bootstrapScripts: [assetMap['/main.js']],
});
response.setHeader('Content-Type', 'text/html');
prelude.pipe(response);
});
```
The client code then reads the same assetMap via `window.assetMap`.
Reading asset paths from build output with assetMap
To handle hashed asset filenames from the build, pass an assetMap prop to the root component:
```js
export default function App({ assetMap }) {
return (
<html>
<head>
<title>My app</title>
<link rel="stylesheet" href={assetMap['styles.css']}></link>
</head>
...
</html>
);
}
```
On the server, render with `<App assetMap={assetMap} />` and provide assetMap to bootstrapScripts.
Converting prerenderToNodeStream stream to string
To render to a static HTML string, read the entire stream:
```js
import { prerenderToNodeStream } from 'react-dom/static';
async function renderToString() {
const {prelude} = await prerenderToNodeStream(<App />, {
bootstrapScripts: ['/main.js']
});
return new Promise((resolve, reject) => {
let data = '';
prelude.on('data', chunk => {
data += chunk;
});
prelude.on('end', () => resolve(data));
prelude.on('error', reject);
});
}
```
prerenderToNodeStream waits for all Suspense data
prerenderToNodeStream waits for all data to load before finishing static HTML generation. It waits for all Suspense boundaries to resolve before resolving. Only data read from a source that activates a Suspense boundary, such as a Promise read with `use`, will suspend during rendering. Suspense does not detect data fetched inside an Effect or event handler.
Aborting prerenderToNodeStream with AbortSignal
You can force prerender to abort after a timeout using an AbortController:
```js
async function renderToString() {
const controller = new AbortController();
setTimeout(() => {
controller.abort()
}, 10000);
try {
const {prelude} = await prerenderToNodeStream(<App />, {
signal: controller.signal,
});
// The prelude contains all HTML prerendered before abort
}
}
```
Any Suspense boundaries with incomplete children are included in the prelude in the fallback state. This supports partial prerendering together with `resumeToPipeableStream` or `resumeAndPrerenderToNodeStream`.
prerenderToNodeStream does not stream incrementally
prerenderToNodeStream waits for the entire app to finish rendering, including all Suspense boundaries, before resolving. It does not support streaming content as it loads and is designed for static site generation (SSG) ahead of time. To stream content as it loads, use a streaming server render API like `renderToPipeableStream`.
prerenderToNodeStream signature and basic usage
prerenderToNodeStream renders a React tree to static HTML as a Node.js Stream. Signature: `const {prelude, postponed} = await prerenderToNodeStream(reactNode, options?)`. It is specific to Node.js environments; environments with Web Streams like Deno and modern edge runtimes should use `prerender` instead.
prerenderToNodeStream parameters
prerenderToNodeStream accepts two parameters: (1) reactNode - a React node to render to HTML, typically representing the entire document starting with the `<html>` tag; (2) options - optional object with properties: bootstrapScriptContent (string placed in inline `<script>` tag), bootstrapScripts (array of string URLs for `<script>` tags), bootstrapModules (like bootstrapScripts but emits `<script type="module">` instead), identifierPrefix (string prefix for IDs generated by `useId`, must match `hydrateRoot`), namespaceURI (root namespace URI, defaults to HTML; pass `'http://www.w3.org/2000/svg'` for SVG or `'http://www.w3.org/1998/Math/MathML'` for MathML), onError (callback fired on server errors), progressiveChunkSize (number of bytes in a chunk), signal (AbortSignal to abort prerendering).
prerenderToNodeStream return value
prerenderToNodeStream returns a Promise that resolves to an object with: prelude - a Node.js Stream of HTML that can be piped to a response or read into a string; postponed - a JSON-serializable opaque object that can be passed to `resumeToPipeableStream` if prerendering did not finish, or null if the prelude contains all content. If rendering fails, the Promise is rejected.
prerenderToNodeStream nonce caveat
The `nonce` option is not available when prerendering because nonces must be unique per request. Including a nonce value in the prerender itself would be inappropriate and insecure if using nonces for Content Security Policy.
prerenderToNodeStream use cases and comparison
prerenderToNodeStream is used for static server-side generation (SSG). Unlike `renderToString`, it waits for all data to load before resolving, making it suitable for generating static HTML for full pages including data fetched with Suspense. To stream content as it loads, use a streaming SSR API like `renderToReadableStream`. The API can be aborted and resumed later with `resumeToPipeableStream` to support partial pre-rendering.
prerenderToNodeStream basic example
Basic example showing how to render a React app to static HTML:
```js
import { prerenderToNodeStream } from 'react-dom/static';
app.use('/', async (request, response) => {
const { prelude } = await prerenderToNodeStream(<App />, {
bootstrapScripts: ['/main.js'],
});
response.setHeader('Content-Type', 'text/plain');
prelude.pipe(response);
});
```
The root component should render the entire document including the `<html>` tag.
App component structure for prerenderToNodeStream
Example root component structure:
```js
export default function App() {
return (
<html>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/styles.css"></link>
<title>My app</title>
</head>
<body>
<Router />
</body>
</html>
);
}
```
React doctype and bootstrap scripts injection
React will inject the doctype and bootstrap `<script>` tags into the resulting HTML stream. The output includes `<!DOCTYPE html>` automatically and the bootstrap scripts are placed after the closing `</html>` tag, for example: `<script src="/main.js" async=""></script>`.
Client-side hydration after prerenderToNodeStream
On the client, the bootstrap script should call `hydrateRoot` to hydrate the entire document:
```js
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';
hydrateRoot(document, <App />);
```
This attaches event listeners to the static server-generated HTML and makes it interactive.
resumeAndPrerenderToNodeStream vs streaming APIs
resumeAndPrerenderToNodeStream waits for all data to load before resolving. To stream content as it loads, use a streaming server-side render (SSR) API like renderToReadableStream instead.
resumeAndPrerenderToNodeStream signature
resumeAndPrerenderToNodeStream continues a prerendered React tree to a static HTML string using a Node.js Stream. It is imported from 'react-dom/static'. The signature is: const {prelude, postponed} = await resumeAndPrerenderToNodeStream(reactNode, postponedState, options?)
resumeAndPrerenderToNodeStream parameters
resumeAndPrerenderToNodeStream takes three parameters: (1) reactNode - the React node you called prerender with, expected to represent the entire document with the App component rendering the html tag; (2) postponedState - the opaque postpone object returned from a prerender API, loaded from storage like redis, a file, or S3; (3) options (optional) - an object with streaming options including signal (an AbortSignal for aborting server rendering) and onError (a callback fired on server errors, defaults to console.error).
resumeAndPrerenderToNodeStream return value
resumeAndPrerenderToNodeStream returns a Promise. If rendering is successful, the Promise resolves to an object containing: prelude (a Web Stream of HTML that can be sent in chunks or read into a string) and postponed (a JSON-serializeable opaque object that can be passed to resumeToNodeStream or resumeAndPrerenderToNodeStream if aborted). If rendering fails, the Promise is rejected.
resumeAndPrerenderToNodeStream nonce caveat
nonce is not an available option when prerendering. Nonces must be unique per request and if you use nonces to secure your application with CSP it would be inappropriate and insecure to include the nonce value in the prerender itself.
resumeAndPrerenderToNodeStream use case
resumeAndPrerenderToNodeStream is used for static server-side generation (SSG). Unlike renderToString, it waits for all data to load before resolving, making it suitable for generating static HTML for a full page including data that needs to be fetched using Suspense. It can be aborted and later either continued with another resumeAndPrerenderToNodeStream or resumed with resume to support partial pre-rendering.
resumeAndPrerenderToNodeStream Node.js specific
resumeAndPrerenderToNodeStream is specific to Node.js. Environments with Web Streams, like Deno and modern edge runtimes, should use prerender instead.
resumeAndPrerenderToNodeStream example
Example usage: import { resumeAndPrerenderToNodeStream } from 'react-dom/static'; import { getPostponedState } from 'storage'; async function handler(request, writable) { const postponedState = getPostponedState(request); const { prelude } = await resumeAndPrerenderToNodeStream(<App />, JSON.parse(postponedState)); prelude.pipe(writable); }