Skip to content

Make indexing opt-in#1353

Open
kevin-dp wants to merge 3 commits intomainfrom
indexing-renaming
Open

Make indexing opt-in#1353
kevin-dp wants to merge 3 commits intomainfrom
indexing-renaming

Conversation

@kevin-dp
Copy link
Contributor

@kevin-dp kevin-dp commented Mar 11, 2026

Summary

Makes indexing explicit and opt-in rather than automatic, allowing users to choose the right index type for their use case and enabling better tree-shaking.

Based on #950 with the ReadOptimizedIndex/WriteOptimizedIndex renaming reverted — keeps the original BasicIndex/BTreeIndex names.

Key changes

  • autoIndex now defaults to off instead of eager
  • BTreeIndex is no longer exported from @tanstack/db main entry point
  • New @tanstack/db/indexing entry point for tree-shakeable indexing
  • To use createIndex() or autoIndex: 'eager', you must set defaultIndexType on the collection
  • Dev mode suggestions warn when indexes would help

Bundle size impact

  • No indexing: ~30% smaller bundle
  • BasicIndex only: ~5 KB (~1.3 KB gzipped)
  • BTreeIndex: ~33 KB (~7.8 KB gzipped)

Test plan

  • Build passes
  • All 2033 tests pass
  • Tests updated to set defaultIndexType where needed

🤖 Generated with Claude Code

@changeset-bot
Copy link

changeset-bot bot commented Mar 11, 2026

🦋 Changeset detected

Latest commit: e3609e7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 14 packages
Name Type
@tanstack/db Minor
@tanstack/angular-db Patch
@tanstack/electric-db-collection Patch
@tanstack/offline-transactions Patch
@tanstack/powersync-db-collection Patch
@tanstack/query-db-collection Patch
@tanstack/react-db Patch
@tanstack/rxdb-db-collection Patch
@tanstack/solid-db Patch
@tanstack/svelte-db Patch
@tanstack/trailbase-db-collection Patch
@tanstack/vue-db Patch
todos Patch
@tanstack/db-example-paced-mutations-demo Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@kevin-dp kevin-dp mentioned this pull request Mar 11, 2026
@kevin-dp kevin-dp force-pushed the indexing-renaming branch 2 times, most recently from 8c77252 to b011fe2 Compare March 11, 2026 13:42
- Make indexing explicit with BasicIndex and BTreeIndex
- autoIndex defaults to 'off', dev mode suggestions warn when indexes would help
- New @tanstack/db/indexing entry point for tree-shakeable indexing
- BasicIndex: lightweight Map + sorted Array for equality and range queries
- BTreeIndex: full-featured O(log n) index for large collections
- Fix pagination when indexes aren't available
- Remove docs folder (now CI-generated)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kevin-dp kevin-dp force-pushed the indexing-renaming branch from b011fe2 to 9c047aa Compare March 11, 2026 13:45
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 11, 2026

More templates

@tanstack/angular-db

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

@tanstack/db

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

@tanstack/db-ivm

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

@tanstack/electric-db-collection

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

@tanstack/offline-transactions

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

@tanstack/powersync-db-collection

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

@tanstack/query-db-collection

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

@tanstack/react-db

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

@tanstack/rxdb-db-collection

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

@tanstack/solid-db

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

@tanstack/svelte-db

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

@tanstack/trailbase-db-collection

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

@tanstack/vue-db

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

commit: 32b524c

@github-actions
Copy link
Contributor

github-actions bot commented Mar 11, 2026

Size Change: +1.83 kB (+1.97%)

Total Size: 95 kB

Filename Size Change
./packages/db/dist/esm/collection/index.js 3.14 kB -183 B (-5.51%)
./packages/db/dist/esm/collection/indexes.js 845 B -253 B (-23.04%) 🎉
./packages/db/dist/esm/collection/lifecycle.js 1.69 kB -66 B (-3.77%)
./packages/db/dist/esm/collection/subscription.js 3.74 kB +34 B (+0.92%)
./packages/db/dist/esm/index.js 2.7 kB -20 B (-0.73%)
./packages/db/dist/esm/indexes/auto-index.js 935 B +193 B (+26.01%) 🚨
./packages/db/dist/esm/indexes/base-index.js 729 B -37 B (-4.83%)
./packages/db/dist/esm/indexes/basic-index.js 2.02 kB +2.02 kB (new file) 🆕
./packages/db/dist/esm/indexes/index-registry.js 797 B +797 B (new file) 🆕
./packages/db/dist/esm/indexes/lazy-index.js 0 B -1.1 kB (removed) 🏆
./packages/db/dist/esm/indexing.js 357 B +357 B (new file) 🆕
./packages/db/dist/esm/query/builder/functions.js 714 B -19 B (-2.59%)
./packages/db/dist/esm/query/compiler/order-by.js 1.45 kB -5 B (-0.34%)
./packages/db/dist/esm/query/live/collection-subscriber.js 2.26 kB -158 B (-6.52%)
./packages/db/dist/esm/utils/array-utils.js 273 B +273 B (new file) 🆕
ℹ️ View Unchanged
Filename Size
./packages/db/dist/esm/collection/change-events.js 1.39 kB
./packages/db/dist/esm/collection/changes.js 1.22 kB
./packages/db/dist/esm/collection/events.js 388 B
./packages/db/dist/esm/collection/mutations.js 2.34 kB
./packages/db/dist/esm/collection/state.js 3.49 kB
./packages/db/dist/esm/collection/sync.js 2.41 kB
./packages/db/dist/esm/deferred.js 207 B
./packages/db/dist/esm/errors.js 4.83 kB
./packages/db/dist/esm/event-emitter.js 748 B
./packages/db/dist/esm/indexes/btree-index.js 2.17 kB
./packages/db/dist/esm/indexes/reverse-index.js 538 B
./packages/db/dist/esm/local-only.js 808 B
./packages/db/dist/esm/local-storage.js 2.1 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/index.js 4.1 kB
./packages/db/dist/esm/query/builder/ref-proxy.js 1.05 kB
./packages/db/dist/esm/query/compiler/evaluators.js 1.43 kB
./packages/db/dist/esm/query/compiler/expressions.js 430 B
./packages/db/dist/esm/query/compiler/group-by.js 2.23 kB
./packages/db/dist/esm/query/compiler/index.js 2.05 kB
./packages/db/dist/esm/query/compiler/joins.js 2.11 kB
./packages/db/dist/esm/query/compiler/select.js 1.09 kB
./packages/db/dist/esm/query/expression-helpers.js 1.43 kB
./packages/db/dist/esm/query/ir.js 673 B
./packages/db/dist/esm/query/live-query-collection.js 360 B
./packages/db/dist/esm/query/live/collection-config-builder.js 5.55 kB
./packages/db/dist/esm/query/live/collection-registry.js 264 B
./packages/db/dist/esm/query/live/internal.js 145 B
./packages/db/dist/esm/query/optimizer.js 2.62 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 927 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 2.9 kB
./packages/db/dist/esm/utils.js 924 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 952 B
./packages/db/dist/esm/utils/cursor.js 457 B
./packages/db/dist/esm/utils/index-optimization.js 1.51 kB
./packages/db/dist/esm/utils/type-guards.js 157 B

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

@github-actions
Copy link
Contributor

github-actions bot commented Mar 11, 2026

Size Change: 0 B

Total Size: 3.85 kB

ℹ️ View Unchanged
Filename Size
./packages/react-db/dist/esm/index.js 225 B
./packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.32 kB
./packages/react-db/dist/esm/useLiveQuery.js 1.34 kB
./packages/react-db/dist/esm/useLiveSuspenseQuery.js 559 B
./packages/react-db/dist/esm/usePacedMutations.js 401 B

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

Tests added on main were calling createIndex() or using autoIndex: 'eager'
without setting defaultIndexType, which is now required.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kevin-dp kevin-dp changed the title Revert BasicIndex/BTreeIndex renaming Make indexing opt-in Mar 11, 2026
@KyleAMathews
Copy link
Collaborator

PR Review Summary

Overall this is a well-designed simplification. Replacing IndexResolver (sync + async union) with IndexConstructor eliminates the 3-state lifecycle and ~250 lines of LazyIndexWrapper/IndexProxy. The tree-shaking story via @tanstack/db/indexing is clean. A few issues worth addressing before merge:


Critical

autoIndex: 'eager' without defaultIndexType silently does nothing in production
packages/db/src/indexes/auto-index.ts:18-27 — When a user explicitly requests autoIndex: 'eager' but forgets defaultIndexType, the console.warn is gated behind isDevModeEnabled() which returns false in production. The function silently returns false and indexing never happens — no error, no warning.

This is a deliberately-requested feature that silently degrades. Consider throwing CollectionConfigurationError at collection construction time (packages/db/src/collection/index.ts:~322) when this invalid configuration is detected:

if (config.autoIndex === 'eager' && !config.defaultIndexType) {
  throw new CollectionConfigurationError(
    `autoIndex: 'eager' requires defaultIndexType to be set. ` +
    `Import an index type and set it:\n` +
    `  import { BasicIndex } from '@tanstack/db/indexing'\n` +
    `  createCollection({ defaultIndexType: BasicIndex, autoIndex: 'eager', ... })`
  )
}

Important

  1. emitIndexSuggestion doesn't protect against onSuggestion callback errorspackages/db/src/indexes/index-registry.ts:76-77. User-provided callback is called without try-catch. A buggy callback could crash query execution with a confusing stack trace.

  2. BasicIndex.remove() swallows errors, leaving index inconsistentpackages/db/src/indexes/basic-index.ts:113-123. When evaluateIndexExpression throws during removal, the catch block returns without cleaning up indexedKeys, leaving phantom keys in the index. Should at minimum call this.indexedKeys.delete(key) in the catch block.

  3. createIndex throws generic Error instead of CollectionConfigurationErrorpackages/db/src/collection/indexes.ts:65-71. The project has a well-established error hierarchy; this should use CollectionConfigurationError to match the pattern and let users catch it with instanceof.


Suggestions

  • Type-level enforcement of autoIndex + defaultIndexType coupling — Currently { autoIndex: 'eager', defaultIndexType: undefined } compiles without error. A discriminated union config type could catch this at compile time:

    | { autoIndex?: 'off'; defaultIndexType?: IndexConstructor<TKey> }
    | { autoIndex: 'eager'; defaultIndexType: IndexConstructor<TKey> }
  • BasicIndex error re-throws lose original stack tracebasic-index.ts:82-86, 162-165. Using { cause: error } would preserve the original stack for debugging.

  • setSizeCallback is now set unconditionally in order-by.ts:282-288. Previously only set when an index existed. In the no-index path, loadNextItems calls requestSnapshot with a fixed limit, but there's no deduplication guard (the pendingOrderedLoadPromise only covers the indexed path). Could cause repeated identical snapshot requests.


Test Coverage Gaps

Priority Gap
1 createIndex() error when no defaultIndexType and no explicit indexType — not tested
2 autoIndex: 'eager' without defaultIndexType behavior — not tested
3 Dev mode suggestion system (index-registry.ts, 170 lines) — zero test coverage
4 BasicIndex (503 lines, recommended default) — no dedicated tests

Strengths

  • Excellent architectural simplification — single indexes map replaces the dual lazyIndexes/resolvedIndexes maps
  • Clean entry point separation for tree-shaking (~30% smaller without indexing)
  • Actionable error messages in createIndex that tell users exactly what to import
  • Well-structured test updates with describe.each for both autoIndex modes

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.

2 participants