tracks03 / 04 cachefor read scale

a cache that's never stale.

A materialized view is a cache the engine keeps exact. Pin your hot queries server-side and every request reads a result that is already correct — the contract is view-after-write == fresh-query, so "stale" stops being a state your system can even be in. Built for public pages where thousands read and few write: a forum's topic list, a storefront, a leaderboard.

01 · pinned queries

warm at zero subscribers.

A normal live query exists while someone subscribes. A pinned query is materialized with a policy that survives zero subscribers — the daemon keeps it exact on every write so the first request of the day is as warm as the thousandth. Pins are viewer-independent, and one onBootId hook re-asserts them if the daemon restarts.

const api = createRindleApiServer<User>({ daemon, queries: registerQueries([topicsPageQuery, hotThreadsQuery]), pinnedQueries: [{ name: "topicsPage", args: { limit: 50 } }],}); await api.assertPins(); // materialized once — warm before the first request

02 · the one-shot read

an endpoint, not a subscription.

Public pages don't want a websocket — they want the current rows, now. handleReadJson resolves a named query once against the warm materialization and returns the rows: the 1-shot endpoint your API server (or edge function) calls to render a page. Same named queries, same authority as the live path — so the cached page and the live app can never disagree.

// your public endpoint: resolve the named query once, return rowsif (req.url === api.routes.read) { return json(await api.handleReadJson(body, ctx));}

The same one-shot read is what server rendering uses to preload first paint — one mechanism from "public forum page" all the way up to "hydrated local-first app".

03 · the economics

pay for the change, not the table.

Re-running a query on every request costs O(table) × readers. Maintaining it costs O(change), once, shared by every viewer. That inversion is what lets one small machine hold a hot public page at load.

cache + invalidate

  • Every write fans out to "which keys are now wrong?"
  • TTLs trade staleness for load, and you tune them forever.
  • The recompute is a full re-query, per key, per miss.
  • Correctness depends on invalidation code you maintain.

pin the query

  • Every write applies its delta to the view — done.
  • Zero staleness, zero TTLs, by construction.
  • One materialization, shared by every viewer.
  • Invalidation code: deleted.

The live wiki board is this track running in public: the real Wikimedia firehose — thousands of edits a minute — held by one pinned query, on one small machine, shared by every viewer.

04 · where it shines

the pages everyone reads.

And when one box stops being enough, the pins scale out: a replicated read fleet serves the same named queries through one affinity-aware endpoint — nothing about your queries changes, there are just more cores maintaining them. See scaling reads.

05 · ship it

your docs path: build a synced app.

Pins, the one-shot read, and SSR are all stops on the synced-app path — and you can run just the cache slice of it: the daemon plus a thin API server. No browser engine, no sync protocol, no websockets required.