Schema Definition
Define your database schema using Drizzle’s type-safe schema builders.
Basic Table
import {
pgTable,
integer,
text,
boolean,
timestamp,
} from 'drizzle-orm/pg-core';
export const users = pgTable('users', {
id: integer('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull(),
active: boolean('active').default(true),
createdAt: timestamp('created_at').defaultNow(),
});
Column Types
Standard Types (from pg-core)
import {
integer,
bigint,
smallint,
real,
doublePrecision,
numeric,
text,
varchar,
char,
boolean,
timestamp,
date,
time,
uuid,
} from 'drizzle-orm/pg-core';
DuckDB-Specific Types
import {
duckDbList,
duckDbArray,
duckDbStruct,
duckDbMap,
duckDbJson,
duckDbTimestamp,
duckDbDate,
duckDbTime,
duckDbBlob,
duckDbInet,
duckDbInterval,
} from '@leonardovida-md/drizzle-neo-duckdb';
See DuckDB Types for detailed usage.
Constraints
Primary Key
const users = pgTable('users', {
id: integer('id').primaryKey(),
});
// Composite primary key
const orderItems = pgTable(
'order_items',
{
orderId: integer('order_id'),
productId: integer('product_id'),
},
(t) => ({
pk: primaryKey({ columns: [t.orderId, t.productId] }),
})
);
Not Null
const users = pgTable('users', {
name: text('name').notNull(),
});
Unique
const users = pgTable('users', {
email: text('email').unique(),
});
// Named unique constraint
const users = pgTable(
'users',
{
email: text('email'),
},
(t) => ({
emailUnique: unique('users_email_unique').on(t.email),
})
);
Default Values
const users = pgTable('users', {
active: boolean('active').default(true),
createdAt: timestamp('created_at').defaultNow(),
data: text('data').default('empty'),
});
Foreign Keys
const posts = pgTable('posts', {
id: integer('id').primaryKey(),
userId: integer('user_id').references(() => users.id),
});
// With explicit constraint
const posts = pgTable(
'posts',
{
id: integer('id').primaryKey(),
userId: integer('user_id'),
},
(t) => ({
userFk: foreignKey({
columns: [t.userId],
foreignColumns: [users.id],
name: 'posts_user_fk',
}),
})
);
Relations
Define relations for relational queries:
import { relations } from 'drizzle-orm';
export const users = pgTable('users', {
id: integer('id').primaryKey(),
name: text('name'),
});
export const posts = pgTable('posts', {
id: integer('id').primaryKey(),
userId: integer('user_id'),
title: text('title'),
});
export const usersRelations = relations(users, ({ many }) => ({
posts: many(posts),
}));
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, {
fields: [posts.userId],
references: [users.id],
}),
}));
Now you can use relational queries:
const db = drizzle(connection, { schema });
const usersWithPosts = await db.query.users.findMany({
with: {
posts: true,
},
});
Schema Organization
Single File (Small Projects)
// schema.ts
import { pgTable, integer, text } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
export const users = pgTable('users', { ... });
export const posts = pgTable('posts', { ... });
export const usersRelations = relations(users, ...);
export const postsRelations = relations(posts, ...);
Multiple Files (Larger Projects)
// schema/users.ts
export const users = pgTable('users', { ... });
export const usersRelations = relations(users, ...);
// schema/posts.ts
export const posts = pgTable('posts', { ... });
export const postsRelations = relations(posts, ...);
// schema/index.ts
export * from './users';
export * from './posts';
Custom Schemas
DuckDB’s default schema is main (not public like Postgres):
import { pgSchema } from 'drizzle-orm/pg-core';
const analyticsSchema = pgSchema('analytics');
export const events = analyticsSchema.table('events', {
id: integer('id').primaryKey(),
type: text('type'),
});
Example: Complete Schema
import {
pgTable,
integer,
text,
doublePrecision,
boolean,
} from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
import {
duckDbJson,
duckDbList,
duckDbStruct,
duckDbTimestamp,
} from '@leonardovida-md/drizzle-neo-duckdb';
// Users table
export const users = pgTable('users', {
id: integer('id').primaryKey(),
email: text('email').notNull().unique(),
name: text('name').notNull(),
preferences: duckDbJson<{
theme: 'light' | 'dark';
notifications: boolean;
}>('preferences'),
tags: duckDbList<string>('tags', 'TEXT'),
createdAt: duckDbTimestamp('created_at', { withTimezone: true }),
});
// Products table
export const products = pgTable('products', {
id: integer('id').primaryKey(),
name: text('name').notNull(),
price: doublePrecision('price').notNull(),
attributes: duckDbStruct<{
brand: string;
category: string;
}>('attributes', {
brand: 'TEXT',
category: 'TEXT',
}),
active: boolean('active').default(true),
});
// Orders table
export const orders = pgTable('orders', {
id: integer('id').primaryKey(),
userId: integer('user_id').references(() => users.id),
total: doublePrecision('total').notNull(),
status: text('status').notNull(),
orderedAt: duckDbTimestamp('ordered_at', { withTimezone: true }),
});
// Relations
export const usersRelations = relations(users, ({ many }) => ({
orders: many(orders),
}));
export const ordersRelations = relations(orders, ({ one }) => ({
user: one(users, {
fields: [orders.userId],
references: [users.id],
}),
}));
See Also
- DuckDB Types - DuckDB-specific types
- Column Types - Complete column reference
- Queries - Using your schema