DEV Community

Cover image for The Ultimate Guide to Drizzle ORM + PostgreSQL (2025 Edition)
Sameer Saleem
Sameer Saleem

Posted on

The Ultimate Guide to Drizzle ORM + PostgreSQL (2025 Edition)

While Prisma dominated the last few years, 2025 is the year of Drizzle ORM. If you’re looking for a lightweight, "serverless-first" ORM that feels like writing raw SQL but provides world-class TypeScript autocompletion, this guide is for you.

1. Project Initialization

We’ll set up a modern Node.js environment using TypeScript. Drizzle is designed to be extremely thin, making it perfect for Edge functions and standard Node backends alike.

mkdir drizzle-postgres-2025
cd drizzle-postgres-2025
npm init -y
npm install typescript tsx @types/node --save-dev
npx tsc --init

Enter fullscreen mode Exit fullscreen mode

2. Install Drizzle and PostgreSQL Driver

Drizzle doesn't use a heavy Rust engine. It’s just TypeScript. We’ll use the postgres package (the fastest JS client) and drizzle-kit for migrations.

npm install drizzle-orm postgres
npm install -D drizzle-kit

Enter fullscreen mode Exit fullscreen mode

3. Configure Your Connection

Create a .env file to hold your PostgreSQL connection string. Whether you’re using Neon, Supabase, or a local Docker instance, the format remains:

DATABASE_URL="postgresql://user:password@localhost:5432/my_db"

Enter fullscreen mode Exit fullscreen mode

4. Define Your Schema in TypeScript

Unlike Prisma, which uses a custom .prisma language, Drizzle uses pure TypeScript. This means you can use functions and variables inside your schema definitions.

Create src/db/schema.ts:

import { pgTable, serial, text, boolean, integer, timestamp } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  email: text('email').unique().notNull(),
  createdAt: timestamp('created_at').defaultNow(),
});

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: text('title').notNull(),
  content: text('content'),
  published: boolean('published').default(false),
  authorId: integer('author_id').references(() => users.id),
});

Enter fullscreen mode Exit fullscreen mode

5. Generate and Push Migrations

Drizzle Kit reads your TypeScript schema and generates the SQL for you.

Create a drizzle.config.ts in your root:

import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  schema: './src/db/schema.ts',
  out: './drizzle',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});

Enter fullscreen mode Exit fullscreen mode

Now, run the migration to sync your DB:

npx drizzle-kit push

Enter fullscreen mode Exit fullscreen mode

6. Instantiate the Client

Create src/db/index.ts. Drizzle is lightweight enough that you don't usually need a complex singleton pattern, but it's good practice for hot-reloading:

import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';

const queryClient = postgres(process.env.DATABASE_URL!);
export const db = drizzle(queryClient, { schema });

Enter fullscreen mode Exit fullscreen mode

7. Performing Type-Safe CRUD

Drizzle gives you two ways to query: SQL-like (for those who love SQL) and Relational Queries (for those who love the Prisma API).

The "Prisma-like" way (Relational):

import { db } from './db';

async function main() {
  // Create a user with a post
  const newUser = await db.insert(users).values({
    name: 'Dev Reader',
    email: 'hello@dev.to',
  }).returning();

  // Fetch users with their posts (The "Prisma" feel)
  const allUsers = await db.query.users.findMany({
    with: {
      posts: true,
    },
  });

  console.log(allUsers);
}

main();

Enter fullscreen mode Exit fullscreen mode

🚀 What Makes Drizzle the 2025 Choice?

  • Zero Code-Gen: You don't need to run npx generate every time you change a field. Your TypeScript types are always in sync with your schema automatically.
  • The "Edge" Advantage: Because Drizzle has no heavy binary engine, it starts up in milliseconds on Vercel Functions or Cloudflare Workers.
  • Drizzle Studio: Just like Prisma Studio, run npx drizzle-kit studio to get a beautiful browser-based UI to explore your PostgreSQL data.
  • SQL Power: If you need to write a complex window function or a specific PostgreSQL extension query, Drizzle stays out of your way and lets you write SQL while still providing types for the result.

Pro-Tip: If you are migrating from Prisma, check out the drizzle-kit introspect command. It can look at your existing database and automatically generate the Drizzle TypeScript schema for you!

Top comments (0)