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
-
Create a new project in Supabase.
-
Get your Supabase URL and Anon Key from the project settings.
-
Create a
todos
table in your Supabase database with the following columns:id
(UUID, primary key)task
(text)completed
(boolean, default: false)
-
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.