Back to articles

Building a Full-Stack App with SvelteKit and a Serverless Database: A Step-by-Step Guide

AuthorMajd Muhtaseb05/27/202515 minutes
Building a Full-Stack App with SvelteKit and a Serverless Database: A Step-by-Step Guide

Introduction

This guide walks you through creating a basic full-stack application using SvelteKit and a serverless database. We'll focus on a simple "todo" application. We'll use Supabase for the serverless database and authentication.

Prerequisites

  • Node.js and npm installed
  • A Supabase account (free tier is sufficient)

Step 1: Create a SvelteKit Project

npm create svelte@latest my-todo-app
cd my-todo-app
npm install

Choose the following options during project creation:

  • "Skeleton project"
  • TypeScript: No
  • ESLint: Yes
  • Prettier: Yes
  • Playwright: No

Step 2: Set up Supabase

  1. Create a new project in Supabase.

  2. Get your Supabase URL and Anon Key from the project settings.

  3. Create a todos table in your Supabase database with the following columns:

    • id (UUID, primary key)
    • task (text)
    • completed (boolean, default: false)
  4. Enable Row Level Security (RLS) on the todos table. For simplicity, create a policy that allows all users to read and write all data. (This is not recommended for production but simplifies this tutorial).

Step 3: Install Supabase Client

npm install @supabase/supabase-js

Step 4: Initialize Supabase Client in SvelteKit

Create a src/lib/supabaseClient.js file:

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;

export const supabase = createClient(supabaseUrl, supabaseAnonKey);

Create a .env file at the root of your project and add your Supabase URL and Anon Key:

VITE_SUPABASE_URL="YOUR_SUPABASE_URL"
VITE_SUPABASE_ANON_KEY="YOUR_SUPABASE_ANON_KEY"

Remember to prefix the environment variables with VITE_ so that SvelteKit exposes them to the browser.

Step 5: Fetch and Display Todos

Edit src/routes/+page.svelte:

<script>
    import { supabase } from '$lib/supabaseClient';
    import { onMount } from 'svelte';

    let todos = [];

    onMount(async () => {
        const { data, error } = await supabase
            .from('todos')
            .select('*')
            .order('id', { ascending: false });

        if (data) {
            todos = data;
        }

        if (error) {
            console.error('Error fetching todos:', error);
        }
    });
</script>

<h1>Todos</h1>

{#each todos as todo (todo.id)}
    <p>{todo.task} - {todo.completed ? 'Completed' : 'Incomplete'}</p>
{/each}

Step 6: Adding a Todo

Add a form to src/routes/+page.svelte:

<script>
    import { supabase } from '$lib/supabaseClient';
    import { onMount } from 'svelte';

    let todos = [];
    let newTask = '';

    onMount(async () => {
        await fetchTodos();
    });

    async function fetchTodos() {
        const { data, error } = await supabase
            .from('todos')
            .select('*')
            .order('id', { ascending: false });

        if (data) {
            todos = data;
        }

        if (error) {
            console.error('Error fetching todos:', error);
        }
    }

    async function addTodo() {
        if (newTask.trim() === '') return;

        const { data, error } = await supabase
            .from('todos')
            .insert([{ task: newTask }])
            .select(); // Select the inserted row

        if (data) {
            todos = [data[0], ...todos]; // Add the new todo to the beginning of the list
            newTask = '';
        }

        if (error) {
            console.error('Error adding todo:', error);
        }
    }
</script>

<h1>Todos</h1>

<form on:submit|preventDefault={addTodo}>
    <input type="text" bind:value={newTask} placeholder="Add a todo" />
    <button type="submit">Add</button>
</form>

{#each todos as todo (todo.id)}
    <p>{todo.task} - {todo.completed ? 'Completed' : 'Incomplete'}</p>
{/each}

Step 7: Running the Application

npm run dev -- --open

Your SvelteKit application should now be running and displaying your todos fetched from Supabase. You can add new todos via the form.

Conclusion

This guide provides a basic framework for building full-stack applications with SvelteKit and a serverless database. You can extend this application by adding features like user authentication, editing todos, and marking todos as complete. Remember to implement proper security measures, especially when handling user data.