Background
TanStack Query provides several options for data initialization and transformation that are not currently exposed in query-db-collection. While TanStack DB has its own patterns (like live queries with .select()), some Query options would enhance the developer experience and provide feature parity.
Current State
- initialData: Only supported in
localOnlyCollectionOptions, not in queryCollectionOptions - placeholderData: Not supported
- structuralSharing: Hard-coded to
true in query.ts:320 - refetchOnWindowFocus/refetchOnReconnect: Not configurable
Proposed Features
1. Initial Data Support
Add initialData option to QueryCollectionConfig for pre-populating collections:
exportinterfaceQueryCollectionConfig<TItem,TError,TQueryKey>{// ... existing options .../** * Initial data to populate the collection before the first fetch * Useful for SSR hydration or cached data from previous sessions */initialData?: Array<TItem>|(()=>Array<TItem>)/** * When the initial data was last updated (for staleness calculations) */initialDataUpdatedAt?: number|(()=>number)}Implementation approach:
- Apply initial data before starting the query observer
- Mark as synced data so it appears immediately in live queries
- Let TanStack Query's staleness logic determine if refetch is needed
2. Structural Sharing Configuration
Allow customizing how data updates are merged:
exportinterfaceQueryCollectionConfig<TItem,TError,TQueryKey>{// ... existing options .../** * How to structurally share data between updates * - true: Use TanStack Query's default structural sharing * - false: Always use new references * - function: Custom sharing logic */structuralSharing?: boolean|((oldData: Array<TItem>,newData: Array<TItem>)=>Array<TItem>)}3. Refetch Triggers
Expose window focus and reconnect options:
exportinterfaceQueryCollectionConfig<TItem,TError,TQueryKey>{// ... existing options .../** * Refetch on window focus * @default true (when data is stale) */refetchOnWindowFocus?: boolean|((query: Query)=>boolean)/** * Refetch on reconnect * @default true (when data is stale) */refetchOnReconnect?: boolean|((query: Query)=>boolean)/** * Network mode for offline behavior * @default 'online' */networkMode?: 'online'|'always'|'offlineFirst'}Implementation Examples
Example 1: SSR Hydration
// Server-side: fetch and serialize initial dataconstinitialTodos=awaitfetchTodos()// Client-side: create collection with initial dataconsttodoCollection=createCollection(queryCollectionOptions({queryKey: ['todos'],queryFn: fetchTodos,getKey: (item)=>item.id,// Hydrate with server datainitialData: initialTodos,initialDataUpdatedAt: Date.now()-60000,// 1 minute old// Keep using server data if fresh enoughstaleTime: 5*60*1000,// 5 minutes
queryClient,}))Example 2: Offline-First Configuration
constofflineCollection=createCollection(queryCollectionOptions({queryKey: ['offline-data'],queryFn: fetchData,getKey: (item)=>item.id,// Load from localStorage if availableinitialData: ()=>{constcached=localStorage.getItem('offline-data')returncached ? JSON.parse(cached) : []},// Don't refetch on focus if we have local datarefetchOnWindowFocus: false,refetchOnReconnect: true,// Work offline-firstnetworkMode: 'offlineFirst',
queryClient,}))Example 3: Custom Structural Sharing
constconfigCollection=createCollection(queryCollectionOptions({queryKey: ['config'],queryFn: fetchConfig,getKey: (item)=>item.key,// Custom structural sharing to preserve references for unchanged config valuesstructuralSharing: (oldData,newData)=>{constresult=[...newData]constnewMap=newMap(newData.map(item=>[item.key,item]))// Reuse references for unchanged itemsoldData.forEach((oldItem,index)=>{constnewItem=newMap.get(oldItem.key)if(newItem&&deepEqual(oldItem,newItem)){result[index]=oldItem// Keep old reference}})returnresult},
queryClient,}))Design Decisions
Why Not placeholderData?
Placeholder data in TanStack Query shows temporary data while loading. In TanStack DB:
- Collections can have
initialData that persists - Live queries show loading states via
isLoading/isReady - The local-first model means you often have real data to show
If needed, developers can implement placeholder UI at the component level.
Benefits
- SSR Support: Initial data enables server-side rendering hydration
- Offline Capability: Better control over offline behavior
- Performance: Custom structural sharing can optimize re-renders
- Feature Parity: Developers familiar with TanStack Query can use known patterns
Testing Requirements
- Test initial data is properly synced to collection
- Test staleness calculations with initialDataUpdatedAt
- Test refetch triggers respect configuration
- Test custom structural sharing functions
- Test network mode behavior
- Test that initial data doesn't interfere with query observer
Migration Guide
All changes are backwards compatible. Existing collections continue to work with defaults:
structuralSharing: truerefetchOnWindowFocus: true (when stale)refetchOnReconnect: true (when stale)- No initial data
Background
TanStack Query provides several options for data initialization and transformation that are not currently exposed in
query-db-collection. While TanStack DB has its own patterns (like live queries with.select()), some Query options would enhance the developer experience and provide feature parity.Current State
localOnlyCollectionOptions, not inqueryCollectionOptionstruein query.ts:320Proposed Features
1. Initial Data Support
Add
initialDataoption toQueryCollectionConfigfor pre-populating collections:Implementation approach:
2. Structural Sharing Configuration
Allow customizing how data updates are merged:
3. Refetch Triggers
Expose window focus and reconnect options:
Implementation Examples
Example 1: SSR Hydration
Example 2: Offline-First Configuration
Example 3: Custom Structural Sharing
Design Decisions
Why Not
placeholderData?Placeholder data in TanStack Query shows temporary data while loading. In TanStack DB:
initialDatathat persistsisLoading/isReadyIf needed, developers can implement placeholder UI at the component level.
Benefits
Testing Requirements
Migration Guide
All changes are backwards compatible. Existing collections continue to work with defaults:
structuralSharing: truerefetchOnWindowFocus: true(when stale)refetchOnReconnect: true(when stale)