Building a Fullstack CRUD App with SvelteKit and Supabase
Introduction
This article guides you through building a simple yet functional CRUD (Create, Read, Update, Delete) application using SvelteKit and Supabase. SvelteKit provides a fast and efficient development experience for building web applications, while Supabase offers a complete backend-as-a-service solution with a PostgreSQL database, authentication, and real-time capabilities.
Prerequisites
- Node.js and npm installed
- A Supabase account and project created
Setting Up Your SvelteKit Project
-
Create a new SvelteKit project:
npm create svelte@latest my-sveltekit-app cd my-sveltekit-app npm install
-
Install the Supabase JavaScript client:
npm install @supabase/supabase-js
Connecting to Supabase
-
Retrieve your Supabase URL and anon key from your Supabase project dashboard.
-
Create a
.env
file in your SvelteKit project root:VITE_SUPABASE_URL="YOUR_SUPABASE_URL" VITE_SUPABASE_ANON_KEY="YOUR_SUPABASE_ANON_KEY"
-
Initialize the Supabase client in
src/lib/supabaseClient.js
:import { createClient } from '@supabase/supabase-js'; import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'; export const supabase = createClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY);
Creating the Data Model (Tasks)
Let's assume we're building a task management application. Create a table named tasks
in your Supabase database with the following columns:
id
(UUID, primary key)task
(text)completed
(boolean, default: false)
Implementing CRUD Operations
1. Reading Tasks (GET)
In src/routes/+page.svelte
:
<script>
import { supabase } from '$lib/supabaseClient';
import { onMount } from 'svelte';
let tasks = [];
onMount(async () => {
const { data, error } = await supabase.from('tasks').select('*').order('id');
if (data) {
tasks = data;
}
if (error) {
console.error('Error fetching tasks:', error);
}
});
</script>
<h1>Tasks</h1>
{#each tasks as task (task.id)}
<div>
<input type="checkbox" checked={task.completed} />
{task.task}
</div>
{/each}
2. Creating Tasks (POST)
Add an input field and button to create new tasks:
<script>
// ... (previous code)
let newTask = '';
async function createTask() {
const { data, error } = await supabase
.from('tasks')
.insert([{ task: newTask }]);
if (data) {
tasks = [...tasks, data[0]]; // Add new task to the local array
newTask = ''; // Clear the input field
}
if (error) {
console.error('Error creating task:', error);
}
}
</script>
// ... (previous code)
<input type="text" bind:value={newTask} placeholder="Add new task" />
<button on:click={createTask}>Add Task</button>
3. Updating Tasks (PUT/PATCH)
Modify the task list to include a function for updating the completed status:
<script>
// ... (previous code)
async function updateTask(task) {
const { error } = await supabase
.from('tasks')
.update({ completed: !task.completed })
.eq('id', task.id);
if (error) {
console.error('Error updating task:', error);
}
}
</script>
{#each tasks as task (task.id)}
<div>
<input type="checkbox" checked={task.completed} on:change={() => updateTask(task)} />
{task.task}
</div>
{/each}
4. Deleting Tasks (DELETE)
Add a delete button to each task:
<script>
// ... (previous code)
async function deleteTask(task) {
const { error } = await supabase
.from('tasks')
.delete()
.eq('id', task.id);
if (error) {
console.error('Error deleting task:', error);
}
}
</script>
{#each tasks as task (task.id)}
<div>
<input type="checkbox" checked={task.completed} on:change={() => updateTask(task)} />
{task.task}
<button on:click={() => deleteTask(task)}>Delete</button>
</div>
{/each}
Conclusion
This article provides a basic foundation for building a CRUD application using SvelteKit and Supabase. You can expand this application by adding features like authentication, real-time updates, and more complex data models. Remember to handle errors gracefully and optimize your code for performance.