Skip to main content

svelte-db

Svelte 5 bindings for TanStack DB. useLiveQuery with Svelte 5 runes ($state, $derived, $effect). Dependency arrays use getter functions (() => value) for reactive props. Direct destructuring breaks reactivity — use dot notation or wrap with $derived. Conditional queries via returning undefined/null. Import from @tanstack/svelte-db (re-exports all of @tanstack/db).

Source facts

Repository
TanStack/db
Last source activity
October 28, 2026 at 02:19
Detected SKILL.md language
English
Stars
3,972
Forks
277

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
svelte-db
description
Svelte 5 bindings for TanStack DB. useLiveQuery with Svelte 5 runes ($state, $derived, $effect). Dependency arrays use getter functions (() => value) for reactive props. Direct destructuring breaks reactivity — use dot notation or wrap with $derived. Conditional queries via returning undefined/null. Import from @tanstack/svelte-db (re-exports all of @tanstack/db).
type
framework
library
db
framework
svelte
library_version
0.6.17
requires
["db-core"]
sources
["TanStack/db:docs/framework/svelte/overview.md","TanStack/db:packages/svelte-db/src/useLiveQuery.svelte.ts"]
This skill builds on db-core. Read it first for collection setup, query builder, and mutation patterns. # TanStack DB — Svelte 5 ## Setup ```svelte <script lang="ts"> import { useLiveQuery, eq, not } from "@tanstack/svelte-db" const todosQuery = useLiveQuery((q) => q .from({ todo: todoCollection }) .where(({ todo }) => not(todo.completed)) .orderBy(({ todo }) => todo.created_at, "asc") ) </script> {#if todosQuery.isLoading} <div>Loading...</div> {:else} <ul> {#each todosQuery.data as todo (todo.id)} <li>{todo.text}</li> {/each} </ul> {/if} ``` `@tanstack/svelte-db` re-exports everything from `@tanstack/db`. ## Hook ### useLiveQuery Returns a reactive object with getter properties: ```ts // Query function — access via dot notation const query = useLiveQuery((q) => q.from({ todo: todoCollection })) // query.data, query.isLoading, query.status, etc. // query.isLoadingError → the first load failed: nothing to show // query.isCrashed → status 'crashed': local storage broke // query.isSyncError → data is shown, but a sync problem is in health // query.health → health tree: one node for the query and one per source // With reactive deps — use GETTER FUNCTIONS let minPriority = $state(5) const query = useLiveQuery( (q) => q .from({ todo: todoCollection }) .where(({ todo }) => gt(todo.priority, minPriority)), [() => minPriority], ) // Config object const query = useLiveQuery({ query: (q) => q.from({ todo: todoCollection }), gcTime: 60000, }) // Pre-created collection const query = useLiveQuery(preloadedCollection) ``` ## Svelte-Specific Patterns ### Destructuring with $derived ```ts // WRONG — breaks reactivity const { data, isLoading } = useLiveQuery(...) // CORRECT — use dot notation const query = useLiveQuery(...) // Access: query.data, query.isLoading // CORRECT — wrap with $derived if you need destructuring const query = useLiveQuery(...) const { data, isLoading } = $derived(query) ``` ### Props in dependency arrays ```svelte <script lang="ts"> let { userId }: { userId: number } = $props() const todosQuery = useLiveQuery( (q) => q.from({ todo: todoCollection }) .where(({ todo }) => eq(todo.userId, userId)), [() => userId] ) </script> ``` ## Includes (Hierarchical Data) When a query uses `include()` for a subquery in `select`, each child field is a live `Collection`. Subscribe to it with `useLiveQuery` in a subcomponent: ```svelte <!-- ProjectList.svelte --> <script lang="ts"> import { useLiveQuery, eq, include } from "@tanstack/svelte-db" import IssueList from "./IssueList.svelte" const projectsQuery = useLiveQuery((q) => q.from({ p: projectsCollection }).select(({ p }) => ({ id: p.id, name: p.name, issues: include( q .from({ i: issuesCollection }) .where(({ i }) => eq(i.projectId, p.id)) .select(({ i }) => ({ id: i.id, title: i.title })), ), })) ) </script> {#each projectsQuery.data as project (project.id)} <div> {project.name} <IssueList issuesCollection={project.issues} /> </div> {/each} ``` ```svelte <!-- IssueList.svelte — subscribes to the child Collection --> <script lang="ts"> import { useLiveQuery } from "@tanstack/svelte-db" let { issuesCollection } = $props() const issuesQuery = useLiveQuery(issuesCollection) </script> {#each issuesQuery.data as issue (issue.id)} <li>{issue.title}</li> {/each} ``` With `toArray()`, child results are plain arrays and the parent re-emits on child changes: ```ts import { toArray, eq } from '@tanstack/svelte-db' const projectsQuery = useLiveQuery((q) => q.from({ p: projectsCollection }).select(({ p }) => ({ id: p.id, name: p.name, issues: toArray( q .from({ i: issuesCollection }) .where(({ i }) => eq(i.projectId, p.id)) .select(({ i }) => ({ id: i.id, title: i.title })), ), })), ) // project.issues is a plain array — no subcomponent needed ``` See db-core/live-queries/SKILL.md for full includes rules (correlation conditions, nested includes, aggregates). ## Common Mistakes ### CRITICAL Passing values instead of getter functions in deps Wrong: ```ts let filter = $state('active') const query = useLiveQuery( (q) => q .from({ todo: todoCollection }) .where(({ todo }) => eq(todo.status, filter)), [filter], ) ``` Correct: ```ts let filter = $state('active') const query = useLiveQuery( (q) => q .from({ todo: todoCollection }) .where(({ todo }) => eq(todo.status, filter)), [() => filter], ) ``` In Svelte 5, deps must be getter functions. Passing values directly captures them at creation time — changes won't trigger re-execution. Source: docs/framework/svelte/overview.md ### HIGH Direct destructuring breaks reactivity Wrong: ```ts const { data, isLoading } = useLiveQuery((q) => q.from({ todo: todoCollection }), ) ``` Correct: ```ts const query = useLiveQuery((q) => q.from({ todo: todoCollection })) // Use query.data, query.isLoading ``` Direct destructuring captures values at creation time. Use dot notation or wrap with `$derived`. Source: packages/svelte-db/src/useLiveQuery.svelte.ts See also: db-core/live-queries/SKILL.md — for query builder API. See also: db-core/mutations-optimistic/SKILL.md — for mutation patterns.
View on GitHub