Because WattleDB is plain PostgreSQL, there's no special driver or adapter — Prisma, Drizzle, TypeORM, whatever you like, all connect normally. The only thing to get right is which connection string does which job. Get that right and everything from migrations to serverless just works.

The rule for every ORM

  • App / query runtime → pooled DATABASE_URL.
  • Migrations → direct DIRECT_URL.
  • Always keep sslmode=require — both endpoints are TLS.

Two URLs, two jobs

Your app makes lots of short queries under load — that's the pooled DATABASE_URL's job (see connection pooling). Migrations create objects and hold longer transactions that a transaction pooler breaks — that's the direct DIRECT_URL's job. Every ORM setup below is just wiring those two strings to those two roles.

Prisma

Prisma has first-class support for exactly this split. Point url at the pooled endpoint and directUrl at the direct one — Prisma uses url at runtime and directUrl for prisma migrate and introspection:

// schema.prisma
datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")   // pooled — app queries
  directUrl = env("DIRECT_URL")     // direct — migrations
}
# .env
DATABASE_URL="postgresql://app:***@<id>.db.wattledb.com.au:PORT/app?sslmode=require&pgbouncer=true"
DIRECT_URL="postgresql://app:***@<id>.db.wattledb.com.au:PORT/app?sslmode=require"

The pgbouncer=true flag tells Prisma it's talking to a transaction pooler, so it manages prepared statements accordingly.

Drizzle

Drizzle uses a Postgres driver directly. For the pooled connection with postgres.js, disable prepared statements so the transaction pooler is happy; use the direct URL in your Drizzle Kit migration config:

// db.ts — runtime, pooled
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";

const client = postgres(process.env.DATABASE_URL!, { prepare: false });
export const db = drizzle(client);
// drizzle.config.ts — migrations, direct
export default {
  schema: "./src/schema.ts",
  dbCredentials: { url: process.env.DIRECT_URL! },
} satisfies Config;

TLS and the CA certificate

Both endpoints require TLS — keep sslmode=require in your connection strings. For verified TLS (recommended in production), download the CA certificate from the console and point your driver at it with sslmode=verify-full and the cert path, so the client checks it's really talking to your database and not a man in the middle.

Common pitfalls