February 10, 2025
How to define schemas, run migrations, and query a serverless Postgres database using Drizzle ORM and Neon.

Drizzle is a TypeScript-first ORM that feels like writing SQL — because it mostly is. There's no magic query builder to learn. Schemas are plain TypeScript objects, queries are composable, and the generated SQL is predictable.
Paired with Neon's serverless Postgres, you get a fully managed database that scales to zero and costs nothing when idle.
// services/db/schema.ts
import { pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: uuid("id").primaryKey().defaultRandom(),
email: text("email").notNull().unique(),
name: text("name"),
createdAt: timestamp("created_at").defaultNow().notNull(),
});
export const posts = pgTable("posts", {
id: uuid("id").primaryKey().defaultRandom(),
title: text("title").notNull(),
body: text("body").notNull(),
authorId: uuid("author_id").references(() => users.id),
createdAt: timestamp("created_at").defaultNow().notNull(),
});Drizzle generates SQL migration files from your schema. Run them with:
pnpm drizzle-kit generate
pnpm drizzle-kit migrateThe drizzle.config.ts at the root points to your schema and database URL:
import { defineConfig } from "drizzle-kit";
export default defineConfig({
schema: "./services/db/schema.ts",
out: "./drizzle",
dialect: "postgresql",
dbCredentials: { url: process.env.DATABASE_URL! },
});// find a user by email
const user = await db.query.users.findFirst({
where: eq(users.email, "ali@example.com"),
});
// list posts with author
const result = await db.query.posts.findMany({
with: { author: true },
orderBy: desc(posts.createdAt),
limit: 10,
});// insert
const [newPost] = await db
.insert(posts)
.values({ title: "Hello", body: "World", authorId: user.id })
.returning();
// update
await db
.update(posts)
.set({ title: "Updated" })
.where(eq(posts.id, newPost.id));Neon splits storage and compute. Your database is always available for reads but compute scales to zero after inactivity — ideal for agency projects where some clients have low traffic. Branching support also makes it easy to test migrations in a staging environment before applying them to production.
Your laboratory instruments should serve you, not the other way around. We're happy to help you.