Every non-trivial web application needs a database, and SvelteKit gives you complete freedom in choosing one. Because SvelteKit runs server-side code through load functions, form actions, and API endpoints, you can connect to any database that has a JavaScript or TypeScript client. The challenge is not whether you can connect — it is choosing the right database and ORM for your project. This guide covers the most popular database options for SvelteKit projects in 2026, with practical setup examples and honest assessments of when to use each one. If you want a pre-configured database setup, Teta provisions a Supabase PostgreSQL database automatically with every new project.
Database Options for SvelteKit
SvelteKit is database-agnostic. It does not bundle or prefer any specific database. Your server-side code (+page.server.ts, +server.ts, hooks.server.ts) runs in a Node.js environment, so any database client that works with Node.js works with SvelteKit.
The main decision points are:
- SQL vs NoSQL. Do you need relational data with joins and transactions, or flexible document storage?
- Managed vs self-hosted. Do you want someone else to handle backups, scaling, and maintenance?
- ORM vs query builder vs raw SQL. How much abstraction do you want between your code and the database?
- Edge compatibility. If you deploy to Cloudflare Workers or other edge runtimes, your database client needs to work outside Node.js.
Let's look at the most popular options.
Supabase (PostgreSQL)
Supabase is the most popular database choice for SvelteKit projects, and for good reason. It provides a hosted PostgreSQL database with a REST API, real-time subscriptions, authentication, file storage, and edge functions — all from a single service.
Setup
npm install @supabase/supabase-js @supabase/ssr
// src/hooks.server.ts
import { createServerClient } from '@supabase/ssr';
import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
import type { Handle } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
event.locals.supabase = createServerClient(
PUBLIC_SUPABASE_URL,
PUBLIC_SUPABASE_ANON_KEY,
{
cookies: {
getAll: () => event.cookies.getAll(),
setAll: (cookiesToSet) => {
cookiesToSet.forEach(({ name, value, options }) => {
event.cookies.set(name, value, { ...options, path: '/' });
});
}
}
}
);
return resolve(event);
};
Querying Data
// src/routes/posts/+page.server.ts
export async function load({ locals: { supabase } }) {
const { data: posts, error } = await supabase
.from('posts')
.select('id, title, excerpt, published_at, author:profiles(name)')
.eq('published', true)
.order('published_at', { ascending: false })
.limit(20);
return { posts: posts ?? [] };
}
When to Use Supabase
- You want a managed PostgreSQL database with zero operational overhead
- You need authentication, file storage, or real-time features alongside your database
- You want Row Level Security so the client can query the database directly (safely)
- You are building a SaaS, marketplace, or app with user-generated content
- You value having a single platform for backend services
Limitations
- The JavaScript client uses PostgREST (HTTP), not a direct PostgreSQL connection. Complex queries with multiple joins or subqueries can be awkward to express.
- Supabase's real-time has a connection limit on the free tier (200 concurrent connections).
- The free tier limits database size to 500 MB.
Prisma ORM
Prisma is the most widely used ORM in the JavaScript/TypeScript ecosystem. It provides a type-safe database client generated from a schema file, supporting PostgreSQL, MySQL, SQLite, MongoDB, and SQL Server.
Setup
npm install prisma @prisma/client
npx prisma init
Define your schema in prisma/schema.prisma:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model Post {
id String @id @default(cuid())
title String
content String
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId String
createdAt DateTime @default(now())
}
model User {
id String @id @default(cuid())
email String @unique
name String
posts Post[]
}
Generate the client and use it in SvelteKit:
// src/lib/server/database.ts
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export default prisma;
// src/routes/posts/+page.server.ts
import prisma from '$lib/server/database';
export async function load() {
const posts = await prisma.post.findMany({
where: { published: true },
include: { author: { select: { name: true } } },
orderBy: { createdAt: 'desc' },
take: 20
});
return { posts };
}
When to Use Prisma
- You want full type safety for database queries with auto-completion
- You prefer defining your schema in code and using migrations
- Your project has complex relational data with many associations
- You are connecting to an existing database and need introspection
Limitations
- Prisma's generated client adds bundle size (can be 5-10 MB in
node_modules) - Does not work on Cloudflare Workers or other edge runtimes without Prisma Accelerate (a paid proxy)
- Complex raw SQL queries require escaping Prisma's abstraction layer
- Cold start time for serverless deployments can be higher due to client initialization
Drizzle ORM
Drizzle is a newer ORM that has gained significant popularity in 2025-2026. It is lighter than Prisma, closer to SQL, and works on edge runtimes.
Setup
npm install drizzle-orm postgres
npm install -D drizzle-kit
Define your schema in TypeScript:
// src/lib/server/schema.ts
import { pgTable, text, boolean, timestamp } from 'drizzle-orm/pg-core';
export const posts = pgTable('posts', {
id: text('id').primaryKey(),
title: text('title').notNull(),
content: text('content').notNull(),
published: boolean('published').default(false),
authorId: text('author_id').notNull(),
createdAt: timestamp('created_at').defaultNow()
});
export const users = pgTable('users', {
id: text('id').primaryKey(),
email: text('email').unique().notNull(),
name: text('name').notNull()
});
// src/lib/server/database.ts
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';
const client = postgres(process.env.DATABASE_URL!);
export const db = drizzle(client, { schema });
// src/routes/posts/+page.server.ts
import { db } from '$lib/server/database';
import { posts, users } from '$lib/server/schema';
import { eq, desc } from 'drizzle-orm';
export async function load() {
const results = await db
.select({
id: posts.id,
title: posts.title,
authorName: users.name
})
.from(posts)
.leftJoin(users, eq(posts.authorId, users.id))
.where(eq(posts.published, true))
.orderBy(desc(posts.createdAt))
.limit(20);
return { posts: results };
}
When to Use Drizzle
- You want a lightweight, SQL-like ORM with full TypeScript types
- You are deploying to edge runtimes (Cloudflare Workers, Deno Deploy)
- You prefer writing queries that look like SQL rather than object-oriented abstractions
- You want faster cold starts than Prisma in serverless environments
Limitations
- Smaller ecosystem and community than Prisma
- Documentation, while improving, is less comprehensive
- Fewer adapters for niche databases
MongoDB
MongoDB is the most popular NoSQL database. It stores data as flexible JSON-like documents rather than rows and columns. While less common in the SvelteKit community than PostgreSQL, it has valid use cases.
Setup
npm install mongodb
// src/lib/server/database.ts
import { MongoClient } from 'mongodb';
const client = new MongoClient(process.env.MONGODB_URL!);
const db = client.db('myapp');
export default db;
// src/routes/posts/+page.server.ts
import db from '$lib/server/database';
export async function load() {
const posts = await db
.collection('posts')
.find({ published: true })
.sort({ createdAt: -1 })
.limit(20)
.toArray();
return { posts };
}
When to Use MongoDB
- Your data is naturally document-shaped (content management, product catalogs, user-generated content with varying structures)
- You need flexible schemas that can evolve without migrations
- You are working with MongoDB Atlas (the managed service) and want global distribution
Limitations
- No joins in the traditional sense (use
$lookupfor aggregation, but it is less efficient than SQL joins) - ACID transactions are supported but more limited than PostgreSQL
- Type safety requires additional tooling (Mongoose or manual type definitions)
SQLite
SQLite is an embedded database that stores everything in a single file. It is the most widely deployed database in the world (it is in every smartphone) and works surprisingly well for web applications.
Setup with better-sqlite3
npm install better-sqlite3
npm install -D @types/better-sqlite3
// src/lib/server/database.ts
import Database from 'better-sqlite3';
const db = new Database('data.db');
// Enable WAL mode for better concurrent read performance
db.pragma('journal_mode = WAL');
export default db;
// src/routes/posts/+page.server.ts
import db from '$lib/server/database';
export async function load() {
const posts = db
.prepare('SELECT id, title, excerpt FROM posts WHERE published = 1 ORDER BY created_at DESC LIMIT 20')
.all();
return { posts };
}
When to Use SQLite
- Small to medium projects where you want simplicity
- Prototyping and development (no external database to manage)
- Read-heavy workloads with moderate write traffic
- Self-hosted apps on a single server (Fly.io with LiteFS for distributed SQLite)
Limitations
- Single-writer limitation (only one write at a time)
- Does not work on serverless or edge platforms (needs file system access)
- Not suitable for high-write-throughput applications
Choosing the Right Database
| Need | Best Choice |
|---|---|
| Full-stack with auth, real-time, storage | Supabase |
| Complex relational data with type safety | Prisma + PostgreSQL |
| Edge deployment with SQL | Drizzle + Neon/Turso |
| Flexible document data | MongoDB Atlas |
| Simple, no external dependencies | SQLite |
| Maximum control, raw SQL | Direct pg or postgres client |
For most new SvelteKit projects, Supabase is the strongest default choice. It gives you a PostgreSQL database, authentication, real-time subscriptions, and file storage from a single service, with a generous free tier. If you need more control over your queries, pair Supabase's PostgreSQL database with Drizzle or Prisma for the best of both worlds.
Server-Side Data Access Patterns
Regardless of which database you choose, SvelteKit provides consistent patterns for accessing data on the server.
Load functions (+page.server.ts) fetch data before the page renders. This is the primary pattern for reading data.
Form actions handle mutations (create, update, delete) with progressive enhancement. Forms work without JavaScript and enhance automatically when JS is available.
API routes (+server.ts) provide REST endpoints for client-side fetches, webhooks, or external integrations.
Hooks (hooks.server.ts) set up database connections and middleware that run on every request.
The key rule: never import database clients in client-side code. Files under $lib/server/ are excluded from client bundles by SvelteKit, so placing your database modules there ensures credentials and connections never leak to the browser. Teta generates this structure automatically when setting up Supabase integration.
FAQ
What database should I use with SvelteKit?
For most projects, Supabase (PostgreSQL) is the best default. It provides a managed database, authentication, real-time subscriptions, and file storage in one service. If you need a more traditional ORM experience, use Prisma or Drizzle with any PostgreSQL provider. For edge deployments, Drizzle with Neon or Turso offers the best compatibility.
Can I use MongoDB with SvelteKit?
Yes, MongoDB works with SvelteKit. Install the official mongodb package and create a client in a $lib/server/ module. Use it in server load functions and form actions. MongoDB is a good choice when your data is naturally document-shaped, but for most web applications with relational data, PostgreSQL is a better fit.
How do I connect to a database in SvelteKit?
Create a database client in a $lib/server/ module (to ensure it never reaches the browser), then import it in your +page.server.ts load functions, form actions, and +server.ts API routes. Set up the connection in hooks.server.ts if you need it available on every request. Use environment variables for connection strings and credentials.
Is Supabase the best database for SvelteKit?
Supabase is the most popular choice and offers the best overall developer experience for SvelteKit projects. Its combination of PostgreSQL, authentication, real-time, and storage eliminates the need to set up multiple services. However, "best" depends on your needs — Prisma offers stronger type-safe queries, Drizzle is lighter for edge deployments, and MongoDB is better for document-oriented data.