convex-sveltekit
SvelteKit-native Convex integration.
Real-time queries. Form spreading. SSR-to-live transport.
Before / After
// +page.server.ts
export const load = async () => {
const client = new ConvexHttpClient(url)
return {
tasks: await client.query(api.tasks.get, {})
}
}
// +page.svelte
const query = useQuery(
api.tasks.get, {},
{ initialData: data.tasks }
)
const tasks = $derived(
query.data ?? data.tasks
)// +page.ts
export const load = () => ({
tasks: convexLoad(api.tasks.get, {})
})
// +page.svelte
const tasks = data.tasks
// Already live. That's it. SSR'd by the load function. Auto-upgraded to real-time WebSocket via SvelteKit's transport hook.
const client = useConvexClient()
let text = $state("")
let pending = $state(false)
async function submit() {
pending = true
await client.mutation(
api.tasks.create, { text }
)
text = ""; pending = false
}
<!-- Wire it all up manually -->
<form onsubmit={submit}>
<input bind:value={text} />
<button disabled={pending}>Add</button>
</form>const form = convexForm(
z.object({ text: z.string() }),
api.tasks.create
)
<!-- Spread like SvelteKit forms -->
<form {...form}>
<input {...form.fields.text.as("text")} />
<button>Add</button>
</form>Features
convexQuery()
Live queries that auto-update via WebSocket. Drop-in replacement for useQuery.
convexForm()
SvelteKit's form DX for Convex mutations. Spread, validate, enhance — no server hop.
convexLoad()
SSR in load functions. Transport hook auto-upgrades to live on the client.
convexCommand()
Programmatic mutations and actions matching SvelteKit's RemoteCommand pattern.
setupConvexAuth()
Better Auth integration with SSR token seeding. No unauthenticated flashes.
convexUser()
SSR-to-live user data. Seeds from JWT, upgrades to Convex subscription.
Live demo
Try it — add, toggle, delete tasks. This is a real Convex backend. Data resets every 5 minutes.
How the transport works
- 1
convexLoad()in your load function fetches data server-side via Convex's HTTP client. - 2
SvelteKit's
transporthook serializes it across the SSR boundary. - 3
On the client,
transport.decodeauto-upgrades to a live WebSocket subscription with SSR data as initial state. - 4
Mutations trigger Convex to push updates to all live queries — no
.refresh()needed.