--- trigger: glob globs: **/*.svelte, **/*.ts, **/*.svelte.ts --- # 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. ```typescript 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.ts` file. ```typescript 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`, `action` for public functions and `internal*` for private ones. --- ## 5. Function Calling from **Svelte** ### 5.1 Install the Convex client ```bash npm i convex @convex-dev/convex-svelte ``` > The `@convex-dev/convex-svelte` package provides a thin wrapper that works with Svelte stores. ### 5.2 Initialise the client (e.g. in `src/lib/convex.ts`) ```typescript 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 ```svelte {#if loading}
Loading…
{:else if error}{error}
{:else if user}{user.email}
{/if} ``` ### 5.4 Using mutations in a component ```svelte {#if error}{error}
{/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.ts` and export the default `crons` object. --- ## 7. File Storage (Backend) > Same as original guide – use `ctx.storage.getUrl()` and query `_storage` for 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`) ```typescript 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`) ```svelte {#if createdId}Created user id: {createdId}
{/if} {#if error}{error}
{/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 `api` object from `convex/_generated/api`. - ✅ All client calls use the `convex` instance from `$lib/convex`. - ✅ Environment variable `VITE_CONVEX_URL` is defined in `.env`. - ✅ Errors are caught and displayed in the UI. - ✅ Types are imported from `convex/_generated/dataModel` when needed. --- ## 12. References - Convex Docs – [Functions](https://docs.convex.dev/functions) - Convex Svelte SDK – [`@convex-dev/convex-svelte`](https://github.com/convex-dev/convex-svelte) - SvelteKit Docs – [Loading Data](https://kit.svelte.dev/docs/loading) --- _Keep these guidelines alongside the existing `svelte-rules.md` so that contributors have a single source of truth for both frontend and backend conventions._