Skip to main content Home Creators tanstack db solid-db
solid-db SolidJS bindings for TanStack DB. useLiveQuery returns an Accessor that doubles as data access (call as function) with state/status properties. Fine-grained reactivity: signal reads MUST happen inside the query function for tracking. Config passed as Accessor (() => config). Built-in Suspense support via createResource and errors through Solid ErrorBoundary. ReactiveMap for state. Import from @tanstack/solid-db (re-exports all of @tanstack/db).
Jump to install Skills Marketplace Discover and explore AI skills built by the community.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Copy promptShow prompt details A direct command skips the review prompt. Inspect the source before running it.
npx skills add https://github.com/TanStack/db --skill solid-dbThe command stays on one line. Scroll horizontally to inspect it before copying.
Prefer a local copy? Download the files currently available to SkillsMP.
Download Zip Downloading... More from this repository
Creating typed collections with createCollection. Adapter selection: queryCollectionOptions (REST/TanStack Query), electricCollectionOptions (ElectricSQL real-time sync), powerSyncCollectionOptions (PowerSync SQLite), rxdbCollectionOptions (RxDB), trailBaseCollectionOptions (TrailBase), localOnlyCollectionOptions, localStorageCollectionOptions. CollectionConfig options: getKey, schema, sync, gcTime, autoIndex (default off), defaultIndexType, syncMode (eager/on-demand, plus progressive for Electric). StandardSchema validation with Zod/Valibot/ArkType. Collection lifecycle (idle/loading/ready/error). Adapter-specific sync patterns including Electric txid tracking, Query direct writes, Query initial data and scoped factories, and PowerSync query-driven sync with onLoad/onLoadSubset hooks.
Building custom collection adapters for new backends. SyncConfig interface: sync function receiving begin, write, commit, markReady, truncate, metadata primitives and returning cleanup, loadSubset, and optional unloadSubset handlers. ChangeMessage format (insert, update, delete). On-demand LoadSubsetOptions (where, orderBy, limit, offset, cursor). Expression parsing: parseWhereExpression, parseOrderByExpression, extractSimpleComparisons, parseLoadSubsetOptions. Collection options creator pattern. rowUpdateMode (partial vs full). Subscription lifecycle and cleanup functions. Persisted sync metadata API (metadata.row and metadata.collection) for storing per-row and per-collection adapter state.
name solid-db description SolidJS bindings for TanStack DB. useLiveQuery returns an Accessor that doubles as data access (call as function) with state/status properties. Fine-grained reactivity: signal reads MUST happen inside the query function for tracking. Config passed as Accessor (() => config). Built-in Suspense support via createResource and errors through Solid ErrorBoundary. ReactiveMap for state. Import from @tanstack/solid-db (re-exports all of @tanstack/db).
type framework library db framework solid library_version 0.6.17 requires ["db-core"] sources ["TanStack/db:docs/framework/solid/overview.md","TanStack/db:packages/solid-db/src/useLiveQuery.ts"]
This skill builds on db-core. Read it first for collection setup, query builder, and mutation patterns.
TanStack DB — SolidJS
Setup
import { useLiveQuery, eq, not } from '@tanstack/solid-db'
import { ErrorBoundary , For , Show , Suspense } from 'solid-js'
function TodoList ( ) {
const todosQuery = useLiveQuery ((q ) =>
q
.from ({ todo : todoCollection })
.where (({ todo } ) => not (todo.completed ))
.orderBy (({ todo } ) => todo.created_at , 'asc' ),
)
return (
<Suspense fallback ={ <div > Loading...</div > }>
<ul >
<For each ={todosQuery()} > {(todo) => <li > {todo.text}</li > }</For >
</ul >
</Suspense >
)
}
@tanstack/solid-db re-exports everything from @tanstack/db.
Hook
useLiveQuery Returns an Accessor<Array<T>> (or Accessor<T | undefined> with findOne) with additional properties. Call it as a function to get data:
const query = useLiveQuery ((q ) => q.from ({ todo : todoCollection }))
const [minPriority, setMinPriority] = createSignal (5 )
const query = useLiveQuery ((q ) =>
q
.from ({ todo : todoCollection })
.where (({ todo } ) => gt (todo.priority , minPriority ())),
)
const query = useLiveQuery (() => ({
query : (q ) => q.from ({ todo : todoCollection }),
gcTime : 60000 ,
}))
const query = useLiveQuery (() => preloadedCollection)
const query = useLiveQuery ((q ) => {
const id = userId ()
if (!id) return undefined
return q
.from ({ todo : todoCollection })
.where (({ todo } ) => eq (todo.userId , id))
})
Solid-Specific Patterns
Signal reads inside query function
const [category, setCategory] = createSignal ('work' )
const query = useLiveQuery ((q ) =>
q
.from ({ todo : todoCollection })
.where (({ todo } ) => eq (todo.category , category ())),
)
const cat = category ()
const query = useLiveQuery ((q ) =>
q.from ({ todo : todoCollection }).where (({ todo } ) => eq (todo.category , cat)),
)
findOne (single result) When the query uses .findOne(), useLiveQuery returns a single object (or undefined) instead of an array:
const userQuery = useLiveQuery ((q ) =>
q
.from ({ user : usersCollection })
.where (({ user } ) => eq (user.id , userId ()))
.findOne (),
)
return <Show when ={userQuery()} > {(user) => <div > {user().name}</div > }</Show >
Suspense integration <ErrorBoundary fallback={(error ) => <div > {error.message}</div > }>
<Suspense fallback ={ <div > Loading...</div > }>
<For each ={todosQuery()} > {(todo) => <li > {todo.text}</li > }</For >
</Suspense >
</ErrorBoundary >
useLiveQuery integrates with Solid's createResource. Use <Suspense> for
loading and <ErrorBoundary> for errors. Reading an errored query throws
through the resource, so do not rely on reading isError after failure.
Includes (Hierarchical Data) When a query uses includes (subqueries in select), each child field is a live Collection by default. Subscribe to it with useLiveQuery in a subcomponent:
function ProjectList ( ) {
const projectsQuery = useLiveQuery ((q ) =>
q.from ({ p : projectsCollection }).select (({ p } ) => ({
id : p.id ,
name : p.name ,
issues : q
.from ({ i : issuesCollection })
.where (({ i } ) => eq (i.projectId , p.id ))
.select (({ i } ) => ({ id : i.id , title : i.title })),
})),
)
return (
<For each ={projectsQuery()} >
{(project) => (
<div >
{project.name}
<IssueList issuesCollection ={project.issues} />
</div >
)}
</For >
)
}
function IssueList (props : { issuesCollection: Collection } ) {
const issuesQuery = useLiveQuery (() => props.issuesCollection )
return <For each ={issuesQuery()} > {(issue) => <div > {issue.title}</div > }</For >
}
Note: wrap the child Collection in an Accessor (() => props.issuesCollection) to match the overload signature.
With toArray(), child results are plain arrays and the parent re-emits on child changes:
import { toArray, eq } from '@tanstack/solid-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 })),
),
})),
)
See db-core/live-queries/SKILL.md for full includes rules (correlation conditions, nested includes, aggregates).
Common Mistakes
HIGH Reading signals outside the query function const [userId] = createSignal (1 )
const id = userId ()
const query = useLiveQuery ((q ) =>
q.from ({ todo : todoCollection }).where (({ todo } ) => eq (todo.userId , id)),
)
const [userId] = createSignal (1 )
const query = useLiveQuery ((q ) =>
q
.from ({ todo : todoCollection })
.where (({ todo } ) => eq (todo.userId , userId ())),
)
Solid's reactivity tracks signal reads inside reactive contexts. Reading outside the query function captures the value at creation time — changes won't trigger re-execution.
Source: docs/framework/solid/overview.md
MEDIUM Using deprecated query.data instead of query() <For each={todosQuery.data }>{(todo ) => <li > {todo.text}</li > }</For >
<For each={todosQuery ()}>{(todo ) => <li > {todo.text}</li > }</For >
query.data is deprecated. Always use query() to access data. If you encounter existing code using .data, migrate it to the function call form.
See also: db-core/live-queries/SKILL.md — for query builder API.
See also: db-core/mutations-optimistic/SKILL.md — for mutation patterns.