Ingestion Strategies

SNAPSHOT ingestion

The simplest of Flux's four ingestion types — for a channel that is always exactly one object. No array handling, no byte-budget eviction, no pagination — just cache it, hydrate it, and replace it wholesale on every update.

Prerequisites
  • A store already registered via register() — see api/register
  • Familiarity with the other three types — see ingestion/collection-all, ingestion/lru, ingestion/paginated
1

Basic usage

Set ingestionType: 'SNAPSHOT' on any channel whose data is a single object rather than a collection.
typescript
1flux.register({
2 store: useSiteConfigStore,
3 channel: 'homepage',
4 event: 'UPDATE',
5 idbKey: 'homepage:latest',
6 ttl: 'long',
7 ingestionType: 'SNAPSHOT',
8 hydrateState: (store, data) => store.getState().setHomepage(data),
9})
2

What qualifies as a SNAPSHOT

Anything that's always exactly one object and never grows into a list — page content, site-wide config, a legal document.
typescript
1// SNAPSHOT is for a channel that is always exactly one object —
2// never an array, never something you'd paginate or evict.
3
4// Typical SNAPSHOT channels:
5flux.register({ channel: 'homepage', ingestionType: 'SNAPSHOT', /* ... */ })
6flux.register({ channel: 'siteConfig', ingestionType: 'SNAPSHOT', /* ... */ })
7flux.register({ channel: 'termsPage', ingestionType: 'SNAPSHOT', /* ... */ })
3

How it's cached

SNAPSHOT is the most direct of the four types in IDB — the object goes straight into a single TTL envelope under the channel's idbKey, with none of the per-item key splitting or eviction accounting that LRU channels require.
typescript
1// SNAPSHOT data is written directly under the full idbKey —
2// there's no per-item splitting and no LRU eviction machinery
3// involved at all. It's the simplest of the four ingestion types
4// in terms of what actually happens in IDB.
5
6// { data: <your object>, cachedAt: <timestamp>, ttl: <resolved ms> }
7// stored at 'global:homepage:latest' (or 'user:{userId}:...' if scoped)
4

The same dispatch path, every time

A SNAPSHOT channel is dispatched identically regardless of which of the three data paths produced it — cold IDB boot, a bootstrap fetch, or a live realtime event.
typescript
1// The same three moments dispatch a SNAPSHOT channel identically:
2
3// IDB cold boot -> dispatchToStore(reg, cachedData, ...)
4// Bootstrap fetch -> dispatchToStore(reg, freshData, ..., generation)
5// Realtime event -> dispatchToStore(reg, event.data, ...)
6
7// hydrateState(store, data) runs if you provided one, otherwise
8// Flux falls back to store.setState(data) directly.
5

Realtime updates replace the object wholesale

There's no partial-merge behavior for SNAPSHOT channels — whatever object a realtime event carries in event.data is handed to the same hydrateState function bootstrap and IDB hydration use.
typescript
1// A realtime event for a SNAPSHOT channel carries the object as
2// event.data, and dispatch treats it exactly like a bootstrap
3// payload — the same hydrateState function runs either way, so a
4// live edit to siteConfig updates the store the same way a fresh
5// bootstrap fetch would.
6
7hydrateState: (store, data) => store.getState().setSiteConfig(data)
8// called with the full updated object, from IDB, bootstrap, or realtime
Send the full object from your backend

Since Flux doesn't merge partial diffs for SNAPSHOT channels itself, make sure your realtime adapter normalizes each event's data field to the complete object, not just the changed fields — the Supabase adapter's partial-diff-vs-full-row handling is covered in adapters/supabase.

6

Choosing the right ingestion type

SNAPSHOT is one of four. Reach for COLLECTION_ALL the moment your data becomes a bounded array rather than a single object.
typescript
1// Picking the right ingestionType:
2
3// SNAPSHOT — one object. homepage, siteConfig, termsPage
4// COLLECTION_ALL — a bounded array, services, team, pricing
5// fetched entirely
6// LRU — detail pages capped products, articles
7// at a byte budget
8// PAGINATED — large datasets with (deferred, Phase 14)
9// virtual view windows
10
11// Defaults to COLLECTION_ALL if ingestionType is omitted entirely —
12// so SNAPSHOT channels should always set it explicitly.

For bounded arrays, see ingestion/collection-all. For byte-budget-capped detail pages, see ingestion/lru. For configuring ingestionType alongside the rest of a registration, see api/register.