Skip to content

feat(query-db): support eager initial data#1683

Open
KyleAMathews wants to merge 3 commits into
mainfrom
query-initial-placeholder-data-design
Open

feat(query-db): support eager initial data#1683
KyleAMathews wants to merge 3 commits into
mainfrom
query-initial-placeholder-data-design

Conversation

@KyleAMathews

@KyleAMathews KyleAMathews commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Adds typed, collection-local initialData and initialDataUpdatedAt support to eager Query Collections. Initial Query responses now materialize immediately as collection rows while retaining TanStack Query's cache identity, freshness, and wrapped-response semantics.

Root Cause

Query Collections already materialized data preloaded into a QueryClient, but they could not declare initial data per collection. Applications sharing one client across many collections therefore had to choose between overly broad client defaults and imperative cache seeding. Forwarding defaults unchanged was also unsafe for on-demand subsets and placeholder data: neither has collection-wide row-membership semantics.

Approach

  • Add typed top-level initialData and initialDataUpdatedAt options using the original Query response type.
  • Forward those options only for eager observers, then reuse the existing select, materialization, and row-ownership pipeline.
  • Reject explicit collection-level initial data in on-demand mode and suppress client-wide initial-data defaults for derived subset observers.
  • Suppress placeholderData defaults because placeholder results are observer-local UI state, not Query cache data suitable for normalized rows.
  • Document the authority, lifecycle, wrapped-response, write, ownership, and persistence semantics.

Key Invariants

  • The Query cache remains authoritative; existing cached or hydrated data wins over a later initializer.
  • Exact Query keys identify shared documents, even when collections share a QueryClient.
  • select materializes rows without replacing the original wrapped response in the Query cache.
  • Stale initial rows remain available during refetch and reconcile through normal ownership rules.
  • Placeholder data and collection-wide initializers never become rows for arbitrary on-demand subsets.
  • Persistence needs no new format or temporary-row metadata.

Non-goals

  • Materializing placeholderData as DB rows.
  • Defining a subset-aware initializer for on-demand collections.
  • Giving each collection a private cache document when it uses the same exact Query key.
  • Changing direct-write or persistence formats.

Trade-offs

On-demand mode rejects explicit initial-data options rather than guessing subset membership. Callers that know an exact derived key can still seed or hydrate that Query cache entry. Eager mode suppresses placeholder defaults to keep observer presentation state out of the collection's shared normalized state.

Verification

pnpm vitest run packages/query-db-collection/tests/query.test.ts --maxWorkers=1
pnpm --filter @tanstack/query-db-collection build
pnpm --filter @tanstack/query-db-collection lint
git diff --check

The focused Query Collection suite covers fresh and stale initial data, function initializers, wrapped response projection, shared clients and exact keys, existing-cache precedence, on-demand rejection/default suppression, and placeholder-default suppression. Lint passes with existing warnings.

Files changed

  • packages/query-db-collection/src/query.ts — adds the public options and observer initialization policy.
  • packages/query-db-collection/src/errors.ts — adds the on-demand configuration error.
  • packages/query-db-collection/tests/query.test.ts — adds initialization and isolation coverage.
  • docs/collections/query-collection.md — documents usage and user-visible semantics.
  • docs/collections/query-initial-placeholder-data-design.md — records authority, ownership, transitions, writes, and persistence decisions.
  • .changeset/young-cats-initialize.md — records the minor package feature.

Closes #346. Advances #1643.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 38f2c92a-a512-4963-96c8-4e20afd2a07c

📥 Commits

Reviewing files that changed from the base of the PR and between 7f0fa36 and 5b3fd1d.

📒 Files selected for processing (6)
  • .changeset/young-cats-initialize.md
  • docs/collections/query-collection.md
  • docs/collections/query-initial-placeholder-data-design.md
  • packages/query-db-collection/src/errors.ts
  • packages/query-db-collection/src/query.ts
  • packages/query-db-collection/tests/query.test.ts

📝 Walkthrough

Walkthrough

Query Collections now support eager initialData and initialDataUpdatedAt, including wrapped-response projection through select. On-demand collections reject collection-level initializers, while placeholder data is prevented from becoming normalized collection rows.

Changes

Eager initial data support

Layer / File(s) Summary
Initial data and placeholder semantics
docs/collections/query-initial-placeholder-data-design.md, docs/collections/query-collection.md
Documents eager initialization, cache precedence and freshness, wrapped-response projection, lifecycle behavior, on-demand limitations, and unsupported placeholder materialization.
Runtime wiring and validation
packages/query-db-collection/src/errors.ts, packages/query-db-collection/src/query.ts, packages/query-db-collection/tests/query.test.ts, .changeset/young-cats-initialize.md
Adds typed initializer options and an on-demand error, configures observer behavior for eager and on-demand modes, prevents placeholder rows, and tests initialization, reconciliation, projection, cache sharing, and defaults.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant QueryCollection
  participant QueryObserver
  participant QueryClient
  QueryCollection->>QueryObserver: configure initialData and select
  QueryObserver->>QueryClient: read or seed query cache
  QueryClient-->>QueryObserver: response and freshness state
  QueryObserver-->>QueryCollection: materialized projected rows
Loading

Possibly related PRs

  • TanStack/db#1653: Updates the same Query Collection documentation compatibility surface.
  • TanStack/db#1654: Clarifies wrapped-response select projection and cached response envelopes.
  • TanStack/db#1682: Contains directly related initial and placeholder data semantics documentation.

Suggested reviewers: kevin-dp

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR implements initialData support, but #346 also calls for structuralSharing, refetchOnWindowFocus/reconnect, and networkMode options, which are not present. Add the remaining query option support from #346 or narrow the issue scope to initial-data-only work.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: eager initial data support for query-db-collection.
Description check ✅ Passed It covers the change summary, behavior, tests, and verification, though it uses different headings than the template.
Out of Scope Changes check ✅ Passed The added docs, design spec, tests, and changeset all align with the eager initial data feature and related placeholder handling.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch query-initial-placeholder-data-design

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: private package registry requires authentication. Disable ESLint in CodeRabbit settings or use public packages.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jul 16, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-db

npm i https://pkg.pr.new/@tanstack/angular-db@1683

@tanstack/browser-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/browser-db-sqlite-persistence@1683

@tanstack/capacitor-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/capacitor-db-sqlite-persistence@1683

@tanstack/cloudflare-durable-objects-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/cloudflare-durable-objects-db-sqlite-persistence@1683

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@1683

@tanstack/db-ivm

npm i https://pkg.pr.new/@tanstack/db-ivm@1683

@tanstack/db-sqlite-persistence-core

npm i https://pkg.pr.new/@tanstack/db-sqlite-persistence-core@1683

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@1683

@tanstack/electron-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/electron-db-sqlite-persistence@1683

@tanstack/expo-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/expo-db-sqlite-persistence@1683

@tanstack/node-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/node-db-sqlite-persistence@1683

@tanstack/offline-transactions

npm i https://pkg.pr.new/@tanstack/offline-transactions@1683

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/@tanstack/powersync-db-collection@1683

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@1683

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@1683

@tanstack/react-native-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/react-native-db-sqlite-persistence@1683

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/@tanstack/rxdb-db-collection@1683

@tanstack/solid-db

npm i https://pkg.pr.new/@tanstack/solid-db@1683

@tanstack/svelte-db

npm i https://pkg.pr.new/@tanstack/svelte-db@1683

@tanstack/tauri-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/tauri-db-sqlite-persistence@1683

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@1683

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@1683

commit: 63025e8

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 125 kB

ℹ️ View Unchanged
Filename Size
packages/db/dist/esm/collection/change-events.js 1.43 kB
packages/db/dist/esm/collection/changes.js 1.38 kB
packages/db/dist/esm/collection/cleanup-queue.js 810 B
packages/db/dist/esm/collection/events.js 434 B
packages/db/dist/esm/collection/index.js 3.62 kB
packages/db/dist/esm/collection/indexes.js 1.99 kB
packages/db/dist/esm/collection/lifecycle.js 1.69 kB
packages/db/dist/esm/collection/mutations.js 2.47 kB
packages/db/dist/esm/collection/state.js 5.48 kB
packages/db/dist/esm/collection/subscription.js 3.74 kB
packages/db/dist/esm/collection/sync.js 2.88 kB
packages/db/dist/esm/collection/transaction-metadata.js 144 B
packages/db/dist/esm/deferred.js 207 B
packages/db/dist/esm/errors.js 5.1 kB
packages/db/dist/esm/event-emitter.js 748 B
packages/db/dist/esm/index.js 3.16 kB
packages/db/dist/esm/indexes/auto-index.js 829 B
packages/db/dist/esm/indexes/base-index.js 767 B
packages/db/dist/esm/indexes/basic-index.js 2.06 kB
packages/db/dist/esm/indexes/btree-index.js 2.19 kB
packages/db/dist/esm/indexes/index-registry.js 820 B
packages/db/dist/esm/indexes/reverse-index.js 557 B
packages/db/dist/esm/live-query-adapter.js 318 B
packages/db/dist/esm/local-only.js 916 B
packages/db/dist/esm/local-storage.js 2.12 kB
packages/db/dist/esm/optimistic-action.js 359 B
packages/db/dist/esm/paced-mutations.js 496 B
packages/db/dist/esm/proxy.js 3.75 kB
packages/db/dist/esm/query/builder/functions.js 1.47 kB
packages/db/dist/esm/query/builder/index.js 5.84 kB
packages/db/dist/esm/query/builder/ref-proxy.js 1.24 kB
packages/db/dist/esm/query/compiler/evaluators.js 1.89 kB
packages/db/dist/esm/query/compiler/expressions.js 430 B
packages/db/dist/esm/query/compiler/group-by.js 3.56 kB
packages/db/dist/esm/query/compiler/index.js 6.67 kB
packages/db/dist/esm/query/compiler/joins.js 2.5 kB
packages/db/dist/esm/query/compiler/lazy-targets.js 923 B
packages/db/dist/esm/query/compiler/order-by.js 1.74 kB
packages/db/dist/esm/query/compiler/select.js 1.53 kB
packages/db/dist/esm/query/effect.js 4.77 kB
packages/db/dist/esm/query/expression-helpers.js 1.43 kB
packages/db/dist/esm/query/ir.js 1.25 kB
packages/db/dist/esm/query/live-query-collection.js 360 B
packages/db/dist/esm/query/live/collection-config-builder.js 9.1 kB
packages/db/dist/esm/query/live/collection-registry.js 264 B
packages/db/dist/esm/query/live/collection-subscriber.js 1.93 kB
packages/db/dist/esm/query/live/internal.js 145 B
packages/db/dist/esm/query/live/utils.js 1.81 kB
packages/db/dist/esm/query/optimizer.js 2.92 kB
packages/db/dist/esm/query/predicate-utils.js 2.97 kB
packages/db/dist/esm/query/query-once.js 359 B
packages/db/dist/esm/query/subset-dedupe.js 960 B
packages/db/dist/esm/scheduler.js 1.3 kB
packages/db/dist/esm/SortedMap.js 1.3 kB
packages/db/dist/esm/strategies/debounceStrategy.js 247 B
packages/db/dist/esm/strategies/queueStrategy.js 428 B
packages/db/dist/esm/strategies/throttleStrategy.js 246 B
packages/db/dist/esm/transactions.js 3.04 kB
packages/db/dist/esm/utils.js 927 B
packages/db/dist/esm/utils/array-utils.js 273 B
packages/db/dist/esm/utils/browser-polyfills.js 304 B
packages/db/dist/esm/utils/btree.js 5.61 kB
packages/db/dist/esm/utils/comparison.js 1.11 kB
packages/db/dist/esm/utils/cursor.js 457 B
packages/db/dist/esm/utils/index-optimization.js 2.39 kB
packages/db/dist/esm/utils/type-guards.js 157 B
packages/db/dist/esm/utils/uuid.js 449 B
packages/db/dist/esm/virtual-props.js 360 B

compressed-size-action::db-package-size

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 4.22 kB

ℹ️ View Unchanged
Filename Size
packages/react-db/dist/esm/index.js 249 B
packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.32 kB
packages/react-db/dist/esm/useLiveQuery.js 1.33 kB
packages/react-db/dist/esm/useLiveQueryEffect.js 355 B
packages/react-db/dist/esm/useLiveSuspenseQuery.js 567 B
packages/react-db/dist/esm/usePacedMutations.js 401 B

compressed-size-action::react-db-package-size

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 125 kB

ℹ️ View Unchanged
Filename Size
packages/db/dist/esm/collection/change-events.js 1.43 kB
packages/db/dist/esm/collection/changes.js 1.38 kB
packages/db/dist/esm/collection/cleanup-queue.js 810 B
packages/db/dist/esm/collection/events.js 434 B
packages/db/dist/esm/collection/index.js 3.62 kB
packages/db/dist/esm/collection/indexes.js 1.99 kB
packages/db/dist/esm/collection/lifecycle.js 1.69 kB
packages/db/dist/esm/collection/mutations.js 2.47 kB
packages/db/dist/esm/collection/state.js 5.48 kB
packages/db/dist/esm/collection/subscription.js 3.74 kB
packages/db/dist/esm/collection/sync.js 2.88 kB
packages/db/dist/esm/collection/transaction-metadata.js 144 B
packages/db/dist/esm/deferred.js 207 B
packages/db/dist/esm/errors.js 5.1 kB
packages/db/dist/esm/event-emitter.js 748 B
packages/db/dist/esm/index.js 3.16 kB
packages/db/dist/esm/indexes/auto-index.js 829 B
packages/db/dist/esm/indexes/base-index.js 767 B
packages/db/dist/esm/indexes/basic-index.js 2.06 kB
packages/db/dist/esm/indexes/btree-index.js 2.19 kB
packages/db/dist/esm/indexes/index-registry.js 820 B
packages/db/dist/esm/indexes/reverse-index.js 557 B
packages/db/dist/esm/live-query-adapter.js 318 B
packages/db/dist/esm/local-only.js 916 B
packages/db/dist/esm/local-storage.js 2.12 kB
packages/db/dist/esm/optimistic-action.js 359 B
packages/db/dist/esm/paced-mutations.js 496 B
packages/db/dist/esm/proxy.js 3.75 kB
packages/db/dist/esm/query/builder/functions.js 1.47 kB
packages/db/dist/esm/query/builder/index.js 5.84 kB
packages/db/dist/esm/query/builder/ref-proxy.js 1.24 kB
packages/db/dist/esm/query/compiler/evaluators.js 1.89 kB
packages/db/dist/esm/query/compiler/expressions.js 430 B
packages/db/dist/esm/query/compiler/group-by.js 3.56 kB
packages/db/dist/esm/query/compiler/index.js 6.67 kB
packages/db/dist/esm/query/compiler/joins.js 2.5 kB
packages/db/dist/esm/query/compiler/lazy-targets.js 923 B
packages/db/dist/esm/query/compiler/order-by.js 1.74 kB
packages/db/dist/esm/query/compiler/select.js 1.53 kB
packages/db/dist/esm/query/effect.js 4.77 kB
packages/db/dist/esm/query/expression-helpers.js 1.43 kB
packages/db/dist/esm/query/ir.js 1.25 kB
packages/db/dist/esm/query/live-query-collection.js 360 B
packages/db/dist/esm/query/live/collection-config-builder.js 9.1 kB
packages/db/dist/esm/query/live/collection-registry.js 264 B
packages/db/dist/esm/query/live/collection-subscriber.js 1.93 kB
packages/db/dist/esm/query/live/internal.js 145 B
packages/db/dist/esm/query/live/utils.js 1.81 kB
packages/db/dist/esm/query/optimizer.js 2.92 kB
packages/db/dist/esm/query/predicate-utils.js 2.97 kB
packages/db/dist/esm/query/query-once.js 359 B
packages/db/dist/esm/query/subset-dedupe.js 960 B
packages/db/dist/esm/scheduler.js 1.3 kB
packages/db/dist/esm/SortedMap.js 1.3 kB
packages/db/dist/esm/strategies/debounceStrategy.js 247 B
packages/db/dist/esm/strategies/queueStrategy.js 428 B
packages/db/dist/esm/strategies/throttleStrategy.js 246 B
packages/db/dist/esm/transactions.js 3.04 kB
packages/db/dist/esm/utils.js 927 B
packages/db/dist/esm/utils/array-utils.js 273 B
packages/db/dist/esm/utils/browser-polyfills.js 304 B
packages/db/dist/esm/utils/btree.js 5.61 kB
packages/db/dist/esm/utils/comparison.js 1.11 kB
packages/db/dist/esm/utils/cursor.js 457 B
packages/db/dist/esm/utils/index-optimization.js 2.39 kB
packages/db/dist/esm/utils/type-guards.js 157 B
packages/db/dist/esm/utils/uuid.js 449 B
packages/db/dist/esm/virtual-props.js 360 B

compressed-size-action::db-package-size

@github-actions

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 4.22 kB

ℹ️ View Unchanged
Filename Size
packages/react-db/dist/esm/index.js 249 B
packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.32 kB
packages/react-db/dist/esm/useLiveQuery.js 1.33 kB
packages/react-db/dist/esm/useLiveQueryEffect.js 355 B
packages/react-db/dist/esm/useLiveSuspenseQuery.js 567 B
packages/react-db/dist/esm/usePacedMutations.js 401 B

compressed-size-action::react-db-package-size

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Initial Data and Query Options Support to query-db-collection

1 participant