npm install @tanstack/svelte-dbSee the Svelte Functions Reference to see the full list of utilities available in the Svelte Adapter.
For comprehensive documentation on writing queries (filtering, joins, aggregations, etc.), see the Live Queries Guide.
Use one DbClient for each browser app and one per server request. DbProvider lets queries resolve collection descriptors against that client:
<script lang="ts">
import { DbClient, DbProvider } from '@tanstack/svelte-db'
import App from './App.svelte'
const client = new DbClient()
</script>
<DbProvider {client}>
<App />
</DbProvider>See SSR and Hydration for server preloading, dehydration, and snapshot handoff.
The useLiveQuery utility creates a live query that automatically updates your component when data changes. It returns reactive values powered by Svelte 5 runes:
<script>
import { useLiveQuery } from '@tanstack/svelte-db'
import { eq } from '@tanstack/db'
const query = useLiveQuery({
query: (q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => eq(todos.completed, false))
.select(({ todos }) => ({ id: todos.id, text: todos.text }))
})
</script>
{#if query.isLoading}
<div>Loading...</div>
{:else}
<ul>
{#each query.data as todo (todo.id)}
<li>{todo.text}</li>
{/each}
</ul>
{/if}Note: With Svelte 5, useLiveQuery returns reactive values through getters. Access query.data and query.isLoading directly (no $ prefix needed).
For ordered, paginated data with live updates, use useLiveInfiniteQuery:
<script>
import { useLiveInfiniteQuery } from '@tanstack/svelte-db'
import { eq } from '@tanstack/db'
let category = $state('news')
const query = useLiveInfiniteQuery(
(q) =>
q
.from({ posts: postsCollection })
.where(({ posts }) => eq(posts.category, category))
.orderBy(({ posts }) => posts.createdAt, 'desc'),
{ pageSize: 20 },
[() => category],
)
</script>
{#each query.data as post (post.id)}
<article>{post.title}</article>
{/each}
{#if query.hasNextPage}
<button
disabled={query.isFetchingNextPage}
onclick={() => query.fetchNextPage()}
>
Load more
</button>
{/if}fetchNextPage() returns a promise that resolves after the page request settles. Failures are exposed through query.error and do not reject the promise.
The query must include orderBy. The dependency array is available only with the query-function form. You can also pass an ordered, pre-created live query collection directly.
useLiveQuery derives identity from structured query IR. Svelte also tracks reactive values read while building the query, so normal builder queries do not need a dependency array or queryKey.
Captured props and state become part of the derived identity:
<script>
import { useLiveQuery } from '@tanstack/svelte-db'
import { gt } from '@tanstack/db'
let { minPriority } = $props()
const query = useLiveQuery({
query: (q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => gt(todos.priority, minPriority))
})
</script>
<div>{query.data.length} high-priority todos</div>When the derived identity changes:
Use queryKey for opaque functional variants such as .fn.where, because DB cannot inspect their closed-over values. Pass reactive key values through a getter:
<script>
import { useLiveQuery } from '@tanstack/svelte-db'
let search = $state('ship')
const query = useLiveQuery({
queryKey: () => [todosCollection.id, 'search', search],
query: (q) =>
q.from({ todos: todosCollection })
.fn.where(({ todos }) => todos.title.includes(search))
})
</script>The legacy dependency array remains supported. Prefer derived identity for structured queries and queryKey for opaque ones.
You can access all status properties directly on the query result:
<script>
import { useLiveQuery } from '@tanstack/svelte-db'
import { eq } from '@tanstack/db'
const query = useLiveQuery((q) =>
q.from({ todos: todosCollection })
.where(({ todos }) => eq(todos.active, true))
)
</script>
<div>
<div>Status: {query.status}</div>
<div>Loading: {query.isLoading}</div>
<div>Ready: {query.isReady}</div>
<div>Total: {query.data.length}</div>
</div>