A page can hold many sections, but a shopper sees only the first few. Deferred hydration lets the theme server-render and hydrate the top sections only. Every section below that point becomes a placeholder with a reserved height, and the engine upgrades it to real content when the shopper scrolls near it.
This reduces the initial HTML, and it reduces the JavaScript that the browser evaluates before the page becomes interactive.
A theme opts in. A theme that declares nothing keeps the previous behaviour.
The declaration
Declare deferredHydration on the theme bundle root, in theme/index.jsx.
export default {
// ... the rest of the theme bundle
deferredHydration: {
ssrSectionCount: 6, // Top body sections to server-render and hydrate
defaultMinHeight: 320, // Pixels reserved for a deferred section with no entry below
sectionMinHeights: { // Pixels reserved per section name
"featured-collection": 640,
"testimonials": 420,
},
rootMargin: "800px 0px", // Upgrade a section when it is this close to the viewport
},
};
ssrSectionCount
ssrSectionCount is the number of top body sections that the engine fully server-renders and
hydrates. The engine counts body sections by position, from the top.
Set it high enough that everything a shopper sees without scrolling is server-rendered. A value of about 6 or more suits most home pages.
The value is a trade. A higher value renders more markup on the server and costs more hydration time. A lower value defers more sections and reserves more placeholders.
Precedence
The theme value wins when it is a number greater than zero. Otherwise the engine uses its own
configured maximum. A theme that declares ssrSectionCount therefore needs no change from the
operator.
The header and the footer are never deferred
The engine always renders header and footer sections. ssrSectionCount applies to body sections
only.
Search engines receive every section
When the request comes from a bot, the engine server-renders all sections and ignores
ssrSectionCount. Deferred hydration therefore does not remove content from a crawler, and it does
not affect indexing.
Reserved heights
A deferred section renders as a placeholder before it upgrades. The placeholder must hold the height that the real content will occupy. If it does not, the page moves when the content arrives.
| Field | Meaning |
|---|---|
sectionMinHeights | Pixels reserved for one named section |
defaultMinHeight | Pixels reserved for a deferred section with no entry in the map |
Give every deferred section that renders content its own sectionMinHeights entry, keyed by the
section name. Calculate the value the same way as a skeleton height:
H = ceil(cardCount / columns) x (cardHeight + rowGap).
Read Section Performance Rules, Rule 3, for the height calculation and the matched skeleton that pairs with this reserve.
Do not give a reserve to a section that can render nothing. A section that returns null when a
flag is off, when the shopper is logged out, or when a list is empty must have no
sectionMinHeights entry. A reserve on such a section leaves permanent empty space.
The operator can also supply reserves through engine configuration. The engine merges the two, and the theme value wins for any section name that appears in both.
rootMargin
rootMargin is the margin that the engine gives its IntersectionObserver. A deferred section
upgrades when it comes within this distance of the viewport.
The default is 800px 0px, which upgrades a section roughly one screen before the shopper reaches
it. Raise it to upgrade earlier and to make a fast scroll safer. Lower it to defer more work.
Client-only sections
A section that cannot render on the server, or that only has content after a client fetch, should declare itself client-only. Add this line to the section source file:
export const ssr = false;
The CLI scans the section source for that exact line and writes ssr: false into the generated
section registry. The engine then renders a placeholder for the section and upgrades it on the
client.
Put the marker in the section source, not in the generated registry. The section-chunking generator rewrites the registry on every build, and it removes a value added by hand. Read Section Chunking for the generator.
A client-only section inside the server-rendered top region upgrades as soon as it mounts. A client-only section below the cutoff waits until the shopper scrolls near it, so its chunk is evaluated outside the hydration window.
Do not add a second gate
The ssr: false marker already defers the section. Do not also wrap the section in a mounted or
isRunningOnClient() check that returns null on the first render. The two gates together collapse
the placeholder to zero height and move the page. Render the skeleton on the first render instead.
Height pinning
After hydration the engine holds the server-rendered heights for a short time, then releases them.
heightPinning tunes that release.
| Field | Default |
|---|---|
idleBufferMs | 2000 |
maxWaitMs | 15000 |
noRicFallbackMs | 10000 |
Leave these at the defaults unless you have measured a reason to change them. The engine accepts a finite number between 0 and 120000. It ignores any other value, keeps the default, and writes a warning to the log.
Route prefetch
routePrefetch declares the routes whose chunks the engine fetches ahead of a likely navigation.
routePrefetch: {
routes: ["product-listing", "product-description", "cart-landing"],
},
Each entry is a route pageType identifier. Declare the three to five routes a shopper most often
opens next, and keep the list short. Omitting routePrefetch disables prefetch, which is a valid
choice rather than a defect.
Verification
- Open a long page and view the page source. Count the fully rendered body sections. The count must
equal
ssrSectionCount. - Confirm that the header and the footer are present in the source.
- Scroll slowly. No deferred section may move the content below it when it upgrades.
- Scroll quickly to the bottom and back. Every section must have real content and correct heights.
- Request the page as a crawler. Every section must be present in the HTML.
- Confirm that a section which renders nothing leaves no empty gap.