SvelteKit
SvelteKit connects to DB9 through any standard PostgreSQL driver over pgwire. DB9 is PostgreSQL-compatible, so no special adapter is needed.
This guide shows how to wire up a SvelteKit app with DB9 using Prisma for schema-first workflows and Drizzle for TypeScript-first query building.
Prerequisites
Section titled “Prerequisites”- A DB9 database (create one)
- Node.js 18+
- SvelteKit 2+
Create a DB9 Database
Section titled “Create a DB9 Database”db9 create --name sveltekit-appdb9 create prints the connection string, with the admin password, once — copy it from the Connection String: line. It has this shape:
postgresql://YOUR_TENANT_ID.admin:YOUR_PASSWORD@pg.d0000.db9.io:5432/postgresYOUR_TENANT_ID is the tenant ID prefix in the generated connection string. Copy the username from the Connection String: line printed by db9 create or from db9 db connect. The examples below use pg.db9.io:5433, which reaches the same server; either host and port works. db9 db status sveltekit-app shows the connection string without the password; if you lose it, db9 db reset-password sveltekit-app sets a new password and prints a new connection string.
Set the connection string as an environment variable:
DATABASE_URL="postgresql://YOUR_TENANT_ID.admin:YOUR_PASSWORD@pg.db9.io:5433/postgres?sslmode=require"Install
Section titled “Install”npx sv create sveltekit-db9cd sveltekit-db9npm install prisma@6 @prisma/client@6npx prisma initSchema
Section titled “Schema”generator client { provider = "prisma-client-js"}
datasource db { provider = "postgresql" url = env("DATABASE_URL")}
model Todo { id Int @id @default(autoincrement()) title String done Boolean @default(false) createdAt DateTime @default(now())}Push the schema to DB9:
npx prisma db pushThis first push works against an empty database. Later schema changes need raw SQL — see Troubleshooting.
Generate the client:
npx prisma generateSingleton client
Section titled “Singleton client”Create a shared Prisma instance to avoid connection exhaustion during development:
import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== 'production') { globalForPrisma.prisma = prisma;}Install
Section titled “Install”npx sv create sveltekit-db9cd sveltekit-db9npm install drizzle-orm pgnpm install -D drizzle-kit @types/pgSchema
Section titled “Schema”import { pgTable, serial, varchar, boolean, timestamp } from 'drizzle-orm/pg-core';
export const todos = pgTable('todos', { id: serial('id').primaryKey(), title: varchar('title', { length: 500 }).notNull(), done: boolean('done').default(false), createdAt: timestamp('created_at', { withTimezone: true }).defaultNow(),});Singleton client
Section titled “Singleton client”import { drizzle } from 'drizzle-orm/node-postgres';import { Pool } from 'pg';
const globalForDb = globalThis as unknown as { pool: Pool };
const pool = globalForDb.pool ?? new Pool({ connectionString: process.env.DATABASE_URL,});
if (process.env.NODE_ENV !== 'production') { globalForDb.pool = pool;}
export const db = drizzle(pool);Create the table with SQL that matches the schema above:
db9 db sql sveltekit-app -q "CREATE TABLE IF NOT EXISTS todos ( id SERIAL PRIMARY KEY, title VARCHAR(500) NOT NULL, done BOOLEAN DEFAULT false, created_at TIMESTAMPTZ DEFAULT now())"drizzle-kit push works only for the first push into a database with no tables and fails on
every later run, so create tables and apply later changes with raw SQL — or manage the schema from
the start with drizzle-kit generate and drizzle-kit migrate. See the
Drizzle guide.
Server Load Function
Section titled “Server Load Function”SvelteKit load functions run on the server, making them the right place to query DB9.
import { prisma } from '$lib/server/prisma';import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => { const todos = await prisma.todo.findMany({ orderBy: { createdAt: 'desc' }, });
return { todos };};import { db } from '$lib/server/db';import { todos } from '$lib/server/schema';import { desc } from 'drizzle-orm';import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => { const allTodos = await db.select().from(todos).orderBy(desc(todos.createdAt));
return { todos: allTodos };};Form Actions
Section titled “Form Actions”SvelteKit form actions handle mutations server-side with progressive enhancement.
import { prisma } from '$lib/server/prisma';import type { Actions, PageServerLoad } from './$types';
export const load: PageServerLoad = async () => { const todos = await prisma.todo.findMany({ orderBy: { createdAt: 'desc' }, }); return { todos };};
export const actions: Actions = { create: async ({ request }) => { const data = await request.formData(); await prisma.todo.create({ data: { title: data.get('title') as string }, }); }, toggle: async ({ request }) => { const data = await request.formData(); const id = Number(data.get('id')); const todo = await prisma.todo.findUniqueOrThrow({ where: { id } }); await prisma.todo.update({ where: { id }, data: { done: !todo.done }, }); },};import { db } from '$lib/server/db';import { todos } from '$lib/server/schema';import { eq, desc, not } from 'drizzle-orm';import type { Actions, PageServerLoad } from './$types';
export const load: PageServerLoad = async () => { const allTodos = await db.select().from(todos).orderBy(desc(todos.createdAt)); return { todos: allTodos };};
export const actions: Actions = { create: async ({ request }) => { const data = await request.formData(); await db.insert(todos).values({ title: data.get('title') as string, }); }, toggle: async ({ request }) => { const data = await request.formData(); const id = Number(data.get('id')); await db .update(todos) .set({ done: not(todos.done) }) .where(eq(todos.id, id)); },};Production Notes
Section titled “Production Notes”- Server-side only: All DB9 queries must run in load functions, form actions, or
+server.tsAPI routes. Files insrc/lib/server/are automatically excluded from client bundles. - Host and port:
pg.db9.io:5433and thepg.d0000.db9.io:5432thatdb9 createprints reach the same server; port5432works on either host. - TLS: Use
sslmode=requirein the connection string for DB9’s hosted service. - Node adapter required: DB9 requires a TCP pgwire connection. Use
@sveltejs/adapter-nodefor deployment — edge adapters (Cloudflare, Vercel Edge) do not support raw TCP sockets.
Install the Node adapter:
npm install @sveltejs/adapter-nodeimport adapter from '@sveltejs/adapter-node';import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
export default { preprocess: vitePreprocess(), kit: { adapter: adapter(), },};Troubleshooting
Section titled “Troubleshooting”ECONNREFUSED on port 5432
Section titled “ECONNREFUSED on port 5432”DB9 accepts port 5432 as well as 5433, so the client is not reaching DB9 at all. A refusal from localhost or 127.0.0.1 means the connection string never reached the driver — check that DATABASE_URL is set in the process that opens the connection.
Edge adapter errors
Section titled “Edge adapter errors”DB9 requires pgwire (TCP), which is not available in edge runtimes. Switch to @sveltejs/adapter-node. Cloudflare and Vercel Edge adapters will not work.
Connection pool exhaustion in development
Section titled “Connection pool exhaustion in development”SvelteKit’s dev server reloads modules on change. Without the singleton pattern shown above, each reload opens a new connection pool. Use the globalThis pattern in src/lib/server/ and restart the dev server to release stale connections.
Run prisma db push only once
Section titled “Run prisma db push only once”prisma db push — used above — works for the initial schema creation against an empty
database. Do not run it again once the tables exist: Prisma does not recognise DB9’s spelling of
a serial column’s default and plans to recreate the sequence behind each autoincrement() id.
For a table named after its model, as here, that second push reports success while pointing id
at a new sequence that starts at 1, so inserts into a table that already has rows fail with
23505 duplicate key value. prisma migrate dev additionally fails at P3014, because DB9
rejects the hyphenated name Prisma gives its shadow database.
Create the initial schema with prisma db push, then apply later changes with raw SQL. See
A second db push fails on autoincrement() ids
for the details.
Next Pages
Section titled “Next Pages”- Prisma — full Prisma integration guide
- Drizzle — full Drizzle integration guide
- Connect — connection strings and authentication
- Production Checklist — deployment readiness