This skill provides guidance for building reactive, real-time full-stack applications using Convex (reactive backend-as-a-service) with TanStack Start (full-stack React meta-framework). The stack provides live-updating queries, type-safe end-to-end development, SSR support, and automatic cache invalidation.
When to Use This Skill
-
Implementing Convex queries, mutations, or actions
-
Setting up or troubleshooting Better Auth authentication
-
Configuring TanStack Router routes and loaders
-
Writing schema definitions and indexes
-
Implementing data fetching patterns (useQuery, useSuspenseQuery)
-
Working with file storage, scheduling, or cron jobs
-
Building AI agents with @convex-dev/agent
-
Debugging SSR or hydration issues
Quick Reference
Essential Imports
// Data fetching (always use cached version)
import { useQuery } from 'convex-helpers/react/cache'
import { useMutation, useAction } from 'convex/react'
// SSR with React Query
import { useSuspenseQuery } from '@tanstack/react-query'
import { convexQuery } from '@convex-dev/react-query'
// API and types
import { api } from '~/convex/_generated/api'
import type { Id, Doc } from '~/convex/_generated/dataModel'
// Backend functions
import { query, mutation, action } from "./_generated/server"
import { v } from "convex/values"
The Skip Pattern
Never call hooks conditionally. Use "skip" instead:
const user = useQuery(api.users.get, userId ? { userId } : "skip")
const org = useQuery(api.orgs.get, user?.orgId ? { orgId: user.orgId } : "skip")
Three-State Query Handling
if (data === undefined) return <Skeleton /> // Loading
if (data === null) return <NotFound /> // Not found
return <Content data={data} /> // Success
Function Syntax (Always Include Returns Validator)
export const getUser = query({
args: { userId: v.id("users") },
returns: v.union(
v.object({ _id: v.id("users"), name: v.string() }),
v.null()
),
handler: async (ctx, args) => {
return await ctx.db.get(args.userId)
},
})
Index Best Practices
// Schema - name includes all fields
.index("by_organizationId_status", ["organizationId", "status"])
// Query - fields in same order as index
.withIndex("by_organizationId_status", (q) =>
q.eq("organizationId", orgId).eq("status", "published")
)
Auth Check (Backend)
import { authComponent } from "./auth"
const user = await authComponent.getAuthUser(ctx)
if (!user) throw new Error("Not authenticated")
Core Principles
-
Use queries for reads - Queries are reactive, cacheable, and consistent
-
Keep functions fast - Finish in < 100ms, work with < a few hundred records
-
Prefer queries/mutations over actions - Actions are for external API calls only
-
Always use indexes - Never do table scans with
.filter() -
Minimize client state - Rely on Convex's real-time sync
Common Anti-Patterns
| import { useQuery } from 'convex/react'
| import { useQuery } from 'convex-helpers/react/cache'
| if (id) useQuery(...)
| useQuery(..., id ? {...} : "skip")
| .filter(x => x.field === val)
| .withIndex("by_field", q => q.eq("field", val))
| Action with ctx.db
| Use ctx.runQuery/runMutation
| `count |
|---|
Reference Files
Load the appropriate reference file based on the task:
| references/01-setup.md
| Project setup, config files, environment variables
| references/02-router.md
| Router setup, root route, file-based routing, layouts
| references/03-auth.md
| Better Auth setup, sign up/in/out, protected routes, SSR auth
| references/04-data-fetching.md
| useQuery, useSuspenseQuery, mutations, loaders, prefetching
| references/05-backend.md
| Schema, queries, mutations, actions, internal functions, HTTP endpoints
| references/06-types.md
| TypeScript patterns, validators, type mapping
| references/07-storage.md
| File upload, download, metadata, deletion
| references/08-scheduling.md
| scheduler.runAfter, cron jobs
| references/09-agents.md
| AI agents, tools, RAG setup
| references/10-frontend.md
| Component patterns, loading states, Tailwind/shadcn
| references/11-permissions.md
| Role hierarchy, feature access patterns
| references/12-deployment.md
| Dev commands, Convex CLI, Vercel deployment
| references/13-quick-reference.md
| Import cheatsheet, common patterns summary
When to Load References
-
Starting a new project: Load
01-setup.md -
Adding authentication: Load
03-auth.md -
Writing backend functions: Load
05-backend.md -
Implementing data fetching: Load
04-data-fetching.md -
Building UI components: Load
10-frontend.md -
Need quick syntax: Load
13-quick-reference.md