Static Prerendering

If a page's data does not change between requests, rendering it per request is waste: render it once at build time, write the HTML to a file, let a CDN serve it. React 7,897 ships that API in a separate module, react-dom/static — prerenderToNodeStream in Node, prerender for Web-stream runtimes.

build.jsx - one render, one file, no serverJSX
import { createWriteStream } from 'node:fs';
import { pipeline } from 'node:stream/promises';
import { prerenderToNodeStream } from 'react-dom/static';
import App from './app.jsx';
import { products } from './data.js';
const page = <html lang="en"><head><title>Catalog</title></head>
  <body><App products={products} /></body></html>;
const { prelude } = await prerenderToNodeStream(page, { bootstrapModules: ['/client.js'] });
await pipeline(prelude, createWriteStream('public/index.html'));

The difference from renderToPipeableStream is the promise. Prerendering resolves only after every Suspense boundary has settled, and the prelude it returns is a complete document — 391 bytes for the catalog above, <!DOCTYPE html>, the injected modulepreload link and all. Nothing streams, because no reader is waiting; in exchange you get a file any static host serves with no Node process behind it. The page still hydrates: bootstrapModules puts the script tag in the file, and hydrateRoot runs as before.

Loop over your data, call this once per page, and you have a generated site. The trade is freshness — a price change means a rebuild — so it fits documentation, marketing pages and catalogs on a schedule, and a per-user dashboard not at all.