SSR with Data Queries FULL
The server renders the page with real data. The query adopts that markup as its starting data and keeps it fresh from there. Unlike other frameworks, there's no loading spinner, flash of empty content, or 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 are kept. 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 is kept 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, with isStale set during flight and rows never cleared. |
What the Server Sends
The server sends rendered markup, and nothing else:
<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 keeps it current 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 display. 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. The attribute holds the machine value and the text holds the displayed one:
<!-- 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 formats. A cell that renders $1,250 holds only the formatted text; put data-seed='{"price":1250}' on the row and the machine number wins the merge, so sorting, totals, and any other arithmetic see 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 holds the data from that point on.
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.
Services, incidents, and the notice are read back out of the HTML with no loading flash, then stay live on polling, focus, and reconnect refreshes.