Drizzle schemas: tables as TypeScript

An ORM (object-relational mapper) is a layer between your code and the database that translates between objects and SQL. Drizzle is the modern, TypeScript-first option for Node. It generates SQL for you, gives you type safety, and stays out of your way when you need raw SQL.

after/db/schema.ts
typescript
import { pgTable, serial, varchar, integer, timestamp } from 'drizzle-orm/pg-core';

export const books = pgTable('books', {
  id: serial('id').primaryKey(),
  title: varchar('title', { length: 255 }).notNull(),
  author: varchar('author', { length: 255 }).notNull(),
  pages: integer('pages').notNull(),
  published: varchar('published', { length: 255 }).notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
});

// Drizzle infers the row type from the schema
export type Book = typeof books.$inferSelect;     // SELECT result shape
export type NewBook = typeof books.$inferInsert;  // INSERT input shape

Tables defined in TypeScript. The database structure and the type definitions live in the same file.

Look at the last two lines. typeof books.$inferSelect gives you the type a SELECT returns, including auto-generated columns like id and createdAt. typeof books.$inferInsert gives you the type for INSERT, where id and createdAt are optional. One source of truth, two perfectly accurate types. No copy-paste, no drift.

You can, and Drizzle will let you when you need it. The reason most teams reach for an ORM is the everyday case: SELECT, INSERT, UPDATE, DELETE on simple tables. The query builder catches typos at compile time, gives you autocomplete, and handles parameterization for you. For the 90 percent case it is faster and safer than raw SQL. For the other 10 percent, you drop down to raw SQL when you need it.

One question remains: how does this TypeScript file become actual tables in Postgres? That is the job of drizzle-kit, the companion CLI. npx drizzle-kit push reads schema.ts and applies it straight to the database, which is perfect while you are iterating locally. For production you use npx drizzle-kit generate instead, which writes the change as a SQL migration file you can review and run deliberately. In this workshop we stay on push: any time you change schema.ts, run it again and the tables catch up.

Quiz: Quiz

Loading practice…