minimal-sveltekit-convex-betterauth Svelte Themes

Minimal Sveltekit Convex Betterauth

minimal-sveltekit-convex-betterauth

Minimal starter for SvelteKit + Convex + Better Auth with:

  • a public landing page,
  • login and registration (name / email / password),
  • a protected section in the /(app) route group,
  • centralized route protection in src/hooks.server.ts,
  • SSR auth state passed to the client.

What it does

  • Better Auth handles login, registration, and session.
  • Convex is the backend and user data source.
  • SvelteKit renders the UI and enforces server-side guards.
  • withServerConvexToken(...) in src/hooks.server.ts passes the token to SSR, so server-side Convex queries see the logged-in user.

How to run

  1. Install dependencies:
npm install
  1. Set required environment variables for auth/Convex if you don't have them yet.

    Most commonly needed:

    • SITE_URL — the app URL used by Better Auth,
    • CONVEX_DEPLOYMENT / Convex URL — depending on your local Convex setup,
    • possibly extra variables for a specific auth provider if you add one later.
  2. Start the app:

npm run dev
  1. Run convex:
npx convex dev

Key places in the code

Auth and backend integration

  • src/convex/auth.ts — Better Auth config on the Convex side.
  • src/convex/auth.config.ts — auth providers config for Convex.
  • src/convex/http.ts — HTTP endpoints for auth/integration.
  • src/lib/auth-client.ts — Better Auth client used in Svelte on the frontend.

SSR and token passing

  • src/hooks.server.ts — the central point:
    • gets the token from cookies,
    • sets event.locals.token,
    • protects the /(app) route group,
    • passes the token to SSR via withServerConvexToken(...).
  • src/routes/+layout.server.ts — fetches SSR auth state via getAuthState().
  • src/routes/+layout.svelte — sets up createSvelteAuthClient(...) and passes authState to the client.

Public and protected pages

  • src/routes/+page.svelte — public landing with a login button.
  • src/routes/login/+page.svelte — minimal login form.
  • src/routes/register/+page.svelte — minimal registration form.
  • src/routes/(app)/app/+page.server.ts — example of fetching user data on the server.
  • src/routes/(app)/app/+page.svelte — protected view after login.

App flow

  1. User visits /.
  2. Clicks Login and goes to /login.
  3. After successful login or registration, lands on the protected /app page.
  4. If not authenticated, src/hooks.server.ts redirects from /(app) to /login.
  5. If already authenticated and visits /login or /register, gets redirected to /app.

Good to know when reading the code

  • The /(app) route group is for organization and protection only — it doesn't change the public URL.
  • SSR user data is fetched in +page.server.ts, not in the client component.
  • authClient.signIn.email(...), authClient.signUp.email(...), and authClient.signOut() are only called on the client in event handlers.
  • You don't need to duplicate guards on every page — all auth logic is centralized in src/hooks.server.ts.

Project structure (summary)

src/
  convex/
    auth.ts
    auth.config.ts
    http.ts
  lib/
    auth-client.ts
  routes/
    +page.svelte
    +layout.server.ts
    +layout.svelte
    login/
    register/
    (app)/app/

Top categories

Loading Svelte Themes