Change Database
Switch from Supabase Postgres to self-hosted Postgres, PlanetScale, Turso, or another database.
KitRocket uses Drizzle ORM, which supports multiple databases. Switching is straightforward — update the config, change the connection string, and run migrations.
Option 1: Self-hosted Postgres
If you want to use your own Postgres instance (e.g., on Railway, Render, or a VPS):
Update connection string
DATABASE_URL="postgresql://user:password@your-host:5432/your-database"
That's it
The Drizzle config and schema already target Postgres. No code changes needed. Push the schema:
pnpm db:push
Option 2: Neon Postgres
Neon is a serverless Postgres with branching.
Update connection string
DATABASE_URL="postgresql://user:password@ep-cool-name-123.us-east-2.aws.neon.tech/neondb?sslmode=require"
Update Drizzle config (optional)
If you want to use Neon's serverless driver for better cold start performance:
pnpm add @neondatabase/serverless
import { neon } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-http";
const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql);
Push the schema:
pnpm db:push
Option 3: PlanetScale (MySQL)
PlanetScale is a serverless MySQL platform.
Install MySQL driver
pnpm add @planetscale/database drizzle-orm/mysql-core
pnpm remove @neondatabase/serverless # if previously installed
Update Drizzle config
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/db/schema",
out: "./src/db/migrations",
dialect: "mysql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
Update database client
import { connect } from "@planetscale/database";
import { drizzle } from "drizzle-orm/planetscale-serverless";
const connection = connect({ url: process.env.DATABASE_URL });
export const db = drizzle(connection);
Convert schema files
Drizzle schema syntax differs between Postgres and MySQL. Update each file in src/db/schema/:
// Before (Postgres):
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
export const users = pgTable("users", { ... });
// After (MySQL):
import { mysqlTable, varchar, datetime } from "drizzle-orm/mysql-core";
export const users = mysqlTable("users", { ... });
Key differences:
| Postgres | MySQL |
|---|---|
pgTable | mysqlTable |
text | varchar(255) |
timestamp | datetime |
uuid | varchar(36) |
Push schema
pnpm db:push
Option 4: Turso (SQLite)
Turso is edge SQLite — great for low-latency reads worldwide.
Install SQLite driver
pnpm add @libsql/client
Update connection string
DATABASE_URL="libsql://your-db-name-your-org.turso.io"
DATABASE_AUTH_TOKEN="your-turso-auth-token"
Update Drizzle config
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./src/db/schema",
out: "./src/db/migrations",
dialect: "sqlite",
dbCredentials: {
url: process.env.DATABASE_URL!,
authToken: process.env.DATABASE_AUTH_TOKEN,
},
});
Update database client
import { createClient } from "@libsql/client";
import { drizzle } from "drizzle-orm/libsql";
const client = createClient({
url: process.env.DATABASE_URL!,
authToken: process.env.DATABASE_AUTH_TOKEN,
});
export const db = drizzle(client);
Convert schema files
// Before (Postgres):
import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
// After (SQLite):
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
export const users = sqliteTable("users", { ... });
SQLite uses integer for dates (Unix timestamps) instead of timestamp.
Push schema
pnpm db:push
After switching
- Update
DATABASE_URLin all environments (local, Vercel, etc.) - Run
pnpm db:pushagainst each database - Test auth flows — Better Auth stores sessions in the database
- Test payment webhooks — subscriptions are stored in the database
- Verify all queries work (some SQL features differ between databases)
Troubleshooting
"relation does not exist"
You forgot to push the schema:
pnpm db:push
"SSL required"
Some providers require SSL. Add ?sslmode=require to your connection string.
Better Auth errors after switching
Better Auth uses the database adapter from Drizzle. If you change the database dialect, make sure the Better Auth adapter matches:
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@/lib/db";
export const auth = betterAuth({
database: drizzleAdapter(db),
// ...
});
The adapter auto-detects the dialect from the Drizzle instance.