Skip to main content
Tables are the foundation of your database schema in Drizzle ORM. Each table is defined with columns and optional constraints like indexes, foreign keys, and checks.

Basic table definition

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

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

Table with constraints

Add indexes, foreign keys, and other constraints using the third parameter:
import { pgTable, serial, text, varchar, timestamp, index } from 'drizzle-orm/pg-core';

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: varchar('title', { length: 255 }).notNull(),
  content: text('content'),
  authorId: integer('author_id').notNull(),
  createdAt: timestamp('created_at').defaultNow(),
}, (table) => [
  index('title_idx').on(table.title),
  index('author_created_idx').on(table.authorId, table.createdAt),
]);
The third parameter must return an array of constraint builders, not an object. The object syntax is deprecated.

Column types function

Use the callback syntax to access column builders directly:
export const users = pgTable('users', (t) => ({
  id: t.serial('id').primaryKey(),
  name: t.text('name').notNull(),
  email: t.varchar('email', { length: 255 }).notNull(),
}));
This provides autocomplete for all available column types without individual imports.

Custom table names

Create a table creator for custom prefixes:
import { pgTableCreator } from 'drizzle-orm/pg-core';

const pgTable = pgTableCreator((name) => `myapp_${name}`);

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
});
// Creates table "myapp_users"

Schema namespaces

PostgreSQL and MySQL support schema namespaces:
import { pgSchema } from 'drizzle-orm/pg-core';

const authSchema = pgSchema('auth');

export const users = authSchema.table('users', {
  id: serial('id').primaryKey(),
  email: varchar('email', { length: 255 }).notNull(),
});
// Creates table "auth"."users"

Row-level security (PostgreSQL)

Enable RLS on PostgreSQL tables:
import { pgTable, serial, text } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
}).enableRLS();
Enabling RLS only adds the ENABLE ROW LEVEL SECURITY clause. You still need to define policies separately.

Complete example

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

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  email: varchar('email', { length: 255 }).notNull().unique(),
  name: text('name').notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
}, (table) => [
  index('email_idx').on(table.email),
]);

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  title: varchar('title', { length: 255 }).notNull(),
  content: text('content'),
  authorId: integer('author_id').notNull().references(() => users.id),
  published: boolean('published').default(false),
  createdAt: timestamp('created_at').defaultNow().notNull(),
  updatedAt: timestamp('updated_at').defaultNow().notNull(),
}, (table) => [
  index('author_idx').on(table.authorId),
  index('published_created_idx').on(table.published, table.createdAt),
]);

API reference

name
string
required
The table name in the database
columns
object | function
required
Column definitions as an object or callback function that receives column builders
extraConfig
function
Optional callback that receives the table columns and returns an array of constraints (indexes, foreign keys, etc.)

Build docs developers (and LLMs) love