01 - What is Drizzle

📋 Jump to Takeaways

The Short Version

Drizzle is a TypeScript ORM that stays as close to SQL as possible. If you know SQL, you already know most of Drizzle. It gives you type safety and autocompletion without hiding the SQL underneath.

Unlike heavier ORMs, Drizzle is a thin layer over SQL. You write queries that look like SQL, and they compile to exactly the SQL you'd expect.

// Drizzle query
const allUsers = await db.select().from(users);
// Runs: SELECT * FROM users

// With a filter
const activeUsers = await db.select().from(users).where(eq(users.active, true));
// Runs: SELECT * FROM users WHERE active = true

The Three Parts

Drizzle has three separate packages:

Package What it does
drizzle-orm The ORM itself. Schema definitions, queries, type inference
drizzle-kit CLI tool. Migrations, schema push, introspection
drizzle-studio Visual database browser (comes with drizzle-kit)

You always need drizzle-orm. You almost always need drizzle-kit for managing your database schema.

Drizzle vs Prisma

If you've used Prisma, here's how Drizzle differs:

Prisma Drizzle
Schema .prisma file (custom DSL) TypeScript files
Queries Custom query engine SQL-like syntax
Code generation Required (prisma generate) None needed
Bundle size Heavy (query engine binary) Lightweight (~50KB)
Edge support Limited Full (Vercel, Cloudflare)
// ❌ Prisma - custom syntax, needs codegen
const users = await prisma.user.findMany({
  where: { active: true },
  select: { name: true, email: true }
});

// ✅ Drizzle - reads like SQL, no codegen
const users = await db
  .select({ name: usersTable.name, email: usersTable.email })
  .from(usersTable)
  .where(eq(usersTable.active, true));

Neither is "better." Prisma is more abstracted. Drizzle is closer to SQL. Pick what fits your mental model.

Setup

Start a new project and install the packages:

mkdir drizzle-app && cd drizzle-app
npm init -y
npm install drizzle-orm postgres
npm install -D drizzle-kit tsx typescript

Add "type": "module" to your package.json so top-level await works:

{
  "type": "module"
}

Setting Up the Database

You need a PostgreSQL database. For local development, install PostgreSQL or use Docker:

# Docker (quickest)
docker run --name mydb -e POSTGRES_PASSWORD=password -p 5432:5432 -d postgres

# Create a database
docker exec -it mydb psql -U postgres -c "CREATE DATABASE myapp"

Create a .env file with your connection string:

DATABASE_URL="postgresql://postgres:password@localhost:5432/myapp"

Defining Your Schema

Your tables are defined in TypeScript. Create src/db/schema.ts:

// src/db/schema.ts
import { pgTable, serial, text } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: serial("id").primaryKey(),
  name: text("name").notNull(),
  email: text("email").notNull().unique(),
});

This is just a preview. The next lesson covers schema definitions in detail.

Configuration

Create drizzle.config.ts in your project root. This tells drizzle-kit where your schema is and how to connect:

// drizzle.config.ts
import { defineConfig } from "drizzle-kit";

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

Now push your schema to create the tables in the database:

npx drizzle-kit push

If you get unknown command 'push', update drizzle-kit: npm install -D drizzle-kit@latest.

Connecting to the Database

Create your database connection in src/db/index.ts:

// src/db/index.ts
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";

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

db is your query interface. client is the raw connection (you'll need it to close the connection when your script finishes).

Running Your First Query

Create src/app.ts:

// src/app.ts
import { db, client } from "./db";
import { users } from "./db/schema";
import { eq } from "drizzle-orm";

// Clean up from previous runs
await db.delete(users).where(eq(users.email, "alice@example.com"));

// Insert a user
await db.insert(users).values({ name: "Alice", email: "alice@example.com" });

// Query all users
const allUsers = await db.select().from(users);
console.log(allUsers);
// [{ id: 1, name: "Alice", email: "alice@example.com" }]

// Close the connection when done
await client.end();

Run it:

npx tsx --env-file=.env src/app.ts

tsx runs TypeScript directly. The --env-file flag loads your .env so process.env.DATABASE_URL is available.

Project Structure

Your project should now look like this:

drizzle-app/
  src/
    db/
      index.ts        # database connection
      schema.ts       # table definitions
    app.ts            # your application code
  drizzle.config.ts   # drizzle-kit config
  .env                # DATABASE_URL goes here
  package.json

Keep your schema in one file to start. You can split it into multiple files later as your schema grows.

Key Takeaways

  • Drizzle is a TypeScript ORM that writes queries close to raw SQL
  • Three parts: drizzle-orm (queries), drizzle-kit (CLI/migrations), Drizzle Studio (visual browser)
  • No code generation step, unlike Prisma
  • Lightweight and works at the edge (Vercel, Cloudflare Workers)
  • Setup: install packages, create .env, define schema, run drizzle-kit push, connect and query
  • The db object is your main interface for all database operations

📝 Ready to test your knowledge?

Answer the quiz below to mark this lesson complete.

© 2026 ByteLearn.dev. Free courses for developers. · Privacy