SSR with Data Queries FULL
The server renders the page with real data. The query adopts that markup as its first materialization and keeps it fresh from there. No loading spinner, no flash of empty content, no duplicate boot payload doing the same work twice.
data-ssr="true".
The Handoff Contract
Inside a data-ssr="true" component, every query shape adopts the server's work instead of redoing it:
| Shape | On boot | First refresh |
|---|---|---|
| List | Server rows stand. Nothing is cleared or rebuilt. | Unchanged data leaves the DOM untouched. The first changed result renders the rows fresh; every refresh after that is keyed and patches in place. |
| Record | Server text stands in every bound field. | Fields patch individually when the fetched record differs. |
| State surface | isLoading stays false, so skeletons and spinners never flash over real content. | The catch-up runs as a stale refresh: isStale during flight, rows never wiped. |
What the Server Sends
Rendered markup. That is the whole list:
<div data-component="ops-dashboard" data-ssr="true">
<!-- Record shape: real text in the bound fields -->
<article data-query="opsUser">
<h2 data-bind="name">Ada Lovelace</h2>
<p data-bind="title">Operations, Engine Division</p>
</article>
<!-- List shape: real rows after the template -->
<tbody data-query="inventory">
<template>
<tr><td data-bind="sku"></td><td data-bind="stock" data-type="number"></td></tr>
</template>
<tr><td data-bind="sku">AX-100</td><td data-bind="stock" data-type="number">45</td></tr>
<tr><td data-bind="sku">BX-200</td><td data-bind="stock" data-type="number">12</td></tr>
</tbody>
</div>
What the Client Runs
wildflower.query('inventory', {
from: '/api/inventory',
key: 'sku',
refresh: ['focus', 'etag:60']
});
wildflower.query('opsUser', {
from: '/api/me',
refresh: 'focus'
});
That is the entire handoff. Inside data-ssr="true", the rendered DOM is the seed: the query parses its starting rows back out of the markup it adopts, using the same fields the bindings declare, with data-type handling coercion. The server's data lives in exactly one place, the HTML, and the freshness ladder owns liveness from there, exactly as on a client-rendered page.
Hidden Fields: data-seed
The parse can only recover what the page displays, and the row key is often a field the page does not. data-seed carries those fields as a small JSON object on the row itself, rendered by the same server loop that renders the row. It merges into the parsed row and wins any overlap, since the attribute is machine truth and the text is display truth:
<!-- Rows display sku and stock; the row key (id) rides data-seed -->
<tbody data-query="inventory">
<template>
<tr><td data-bind="sku"></td><td data-bind="stock" data-type="number"></td></tr>
</template>
<tr data-seed='{"id":811}'><td data-bind="sku">AX-100</td><td data-bind="stock" data-type="number">45</td></tr>
<tr data-seed='{"id":812}'><td data-bind="sku">BX-200</td><td data-bind="stock" data-type="number">12</td></tr>
</tbody>
wildflower.query('inventory', {
from: '/api/inventory',
key: 'id', // matched from the data-seed fields
refresh: ['focus', 'etag:60']
});
The same convention covers values the display dresses up. A cell that renders $1,250 holds display truth only; put data-seed='{"price":1250}' on the row and the machine number wins the merge, so sorting, totals, and anything else arithmetic sees the real value from first paint. The live example above does exactly this, computing an inventory total from seeded prices before the first fetch runs.
For a record, the same attribute sits on the query element: <article data-query="me" data-seed='{"userId":42}'>. Each datum still exists exactly once on the wire: visible fields as text, hidden fields in the attribute of the row they belong to. The attribute is read once at adoption and never needs maintaining afterward, since the store owns the data from there.
Row identity is what keeps refreshes cheap: with a key present, parsed or seeded, every refresh after the first framework render patches rows in place. Client-rendered pages, which have no markup to parse, can seed programmatically with the initial: option instead; it always wins over the parse.
initial, treats that fetch as a stale refresh rather than a load: isLoading stays false, isStale flags the catch-up, and content stays put. Client-rendered pages can opt in with an initial seed of their own.
The Payload Math
A page built this way sends its data once, as HTML. There is no seed blob, no framework boot payload that re-describes the page, and no hydration pass that re-renders it. The server's render is not a placeholder to be replaced. It is the first result of a standing query that happens to have run on the other side of the wire.