7.6 KiB
Convex + Svelte Guidelines
Overview
These guidelines describe how to write Convex backend code and consume it from a Svelte (SvelteKit) frontend. The syntax for Convex functions stays exactly the same, but the way you import and call them from the client differs from a React/Next.js project. Below you will find the adapted sections from the original Convex style guide with Svelte‑specific notes.
1. Function Syntax (Backend)
No change – keep the new Convex function syntax.
import {
query,
mutation,
action,
internalQuery,
internalMutation,
internalAction
} from './_generated/server';
import { v } from 'convex/values';
export const getUser = query({
args: { userId: v.id('users') },
returns: v.object({ name: v.string(), email: v.string() }),
handler: async (ctx, args) => {
const user = await ctx.db.get(args.userId);
if (!user) throw new Error('User not found');
return { name: user.name, email: user.email };
}
});
2. HTTP Endpoints (Backend)
No change – keep the same
convex/http.tsfile.
import { httpRouter } from 'convex/server';
import { httpAction } from './_generated/server';
const http = httpRouter();
http.route({
path: '/api/echo',
method: 'POST',
handler: httpAction(async (ctx, req) => {
const body = await req.bytes();
return new Response(body, { status: 200 });
})
});
3. Validators (Backend)
No change – keep the same validators (
v.string(),v.id(), etc.).
4. Function Registration (Backend)
No change – use
query,mutation,actionfor public functions andinternal*for private ones.
5. Function Calling from Svelte
5.1 Install the Convex client
npm i convex @convex-dev/convex-svelte
The
@convex-dev/convex-sveltepackage provides a thin wrapper that works with Svelte stores.
5.2 Initialise the client (e.g. in src/lib/convex.ts)
import { createConvexClient } from '@convex-dev/convex-svelte';
export const convex = createConvexClient({
url: import.meta.env.VITE_CONVEX_URL // set in .env
});
5.3 Using queries in a component
<script lang="ts">
import { convex } from '$lib/convex';
import { onMount } from 'svelte';
import { api } from '../convex/_generated/api';
let user: { name: string; email: string } | null = null;
let loading = true;
let error: string | null = null;
onMount(async () => {
try {
user = await convex.query(api.users.getUser, { userId: 'some-id' });
} catch (e) {
error = (e as Error).message;
} finally {
loading = false;
}
});
</script>
{#if loading}
<p>Loading…</p>
{:else if error}
<p class="error">{error}</p>
{:else if user}
<h2>{user.name}</h2>
<p>{user.email}</p>
{/if}
5.4 Using mutations in a component
<script lang="ts">
import { convex } from '$lib/convex';
import { api } from '../convex/_generated/api';
let name = '';
let creating = false;
let error: string | null = null;
async function createUser() {
creating = true;
error = null;
try {
const userId = await convex.mutation(api.users.createUser, { name });
console.log('Created user', userId);
} catch (e) {
error = (e as Error).message;
} finally {
creating = false;
}
}
</script>
<input bind:value={name} placeholder="Name" />
<button on:click={createUser} disabled={creating}>Create</button>
{#if error}<p class="error">{error}</p>{/if}
5.5 Using actions (Node‑only) from Svelte
Actions run in a Node environment, so they cannot be called directly from the browser. Use a mutation that internally calls the action, or expose a HTTP endpoint that triggers the action.
6. Scheduler / Cron (Backend)
Same as original guide – define
crons.tsand export the defaultcronsobject.
7. File Storage (Backend)
Same as original guide – use
ctx.storage.getUrl()and query_storagefor metadata.
8. TypeScript Helpers (Backend)
Keep using
Id<'table'>from./_generated/dataModel.
9. Svelte‑Specific Tips
| Topic | Recommendation |
|---|---|
| Store‑based data | If you need reactive data across many components, wrap convex.query in a Svelte store (readable, writable). |
| Error handling | Use try / catch around every client call; surface the error in the UI. |
| SSR / SvelteKit | Calls made in load functions run on the server; you can use convex.query there without worrying about the browser environment. |
| Environment variables | Prefix with VITE_ for client‑side access (import.meta.env.VITE_CONVEX_URL). |
| Testing | Use the Convex mock client (createMockConvexClient) provided by @convex-dev/convex-svelte for unit tests. |
10. Full Example (SvelteKit + Convex)
10.1 Backend (convex/users.ts)
import { mutation, query } from './_generated/server';
import { v } from 'convex/values';
export const createUser = mutation({
args: { name: v.string() },
returns: v.id('users'),
handler: async (ctx, args) => {
return await ctx.db.insert('users', { name: args.name });
}
});
export const getUser = query({
args: { userId: v.id('users') },
returns: v.object({ name: v.string() }),
handler: async (ctx, args) => {
const user = await ctx.db.get(args.userId);
if (!user) throw new Error('Not found');
return { name: user.name };
}
});
10.2 Frontend (src/routes/+page.svelte)
<script lang="ts">
import { convex } from '$lib/convex';
import { api } from '$lib/convex/_generated/api';
import { onMount } from 'svelte';
let name = '';
let createdId: string | null = null;
let loading = false;
let error: string | null = null;
async function create() {
loading = true;
error = null;
try {
createdId = await convex.mutation(api.users.createUser, { name });
} catch (e) {
error = (e as Error).message;
} finally {
loading = false;
}
}
</script>
<input bind:value={name} placeholder="Your name" />
<button on:click={create} disabled={loading}>Create user</button>
{#if createdId}<p>Created user id: {createdId}</p>{/if}
{#if error}<p class="error">{error}</p>{/if}
11. Checklist for New Files
- ✅ All Convex functions use the new syntax (
query({ … })). - ✅ Every public function has argument and return validators.
- ✅ Svelte components import the generated
apiobject fromconvex/_generated/api. - ✅ All client calls use the
convexinstance from$lib/convex. - ✅ Environment variable
VITE_CONVEX_URLis defined in.env. - ✅ Errors are caught and displayed in the UI.
- ✅ Types are imported from
convex/_generated/dataModelwhen needed.
12. References
- Convex Docs – Functions
- Convex Svelte SDK –
@convex-dev/convex-svelte - SvelteKit Docs – Loading Data
Keep these guidelines alongside the existing svelte-rules.md so that contributors have a single source of truth for both frontend and backend conventions.