Foreign Key References in Drizzle ORM
Learn how SQL FOREIGN KEY constraints and inline REFERENCES are converted to Drizzle ORM's .references() chain method for type-safe foreign key definitions.
Detailed Explanation
Foreign Keys in Drizzle
Drizzle handles foreign keys through the .references() chain method on column builders. This approach keeps the foreign key definition inline with the column it applies to, making the relationship immediately visible.
Inline REFERENCES
SQL:
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
author_id INTEGER NOT NULL REFERENCES users(id)
);
Drizzle:
export const posts = pgTable("posts", {
id: serial("id").primaryKey(),
title: varchar("title", { length: 255 }).notNull(),
authorId: integer("author_id").notNull().references(() => users.id),
});
Table-Level FOREIGN KEY
SQL:
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
post_id INTEGER NOT NULL,
user_id INTEGER NOT NULL,
body TEXT NOT NULL,
FOREIGN KEY (post_id) REFERENCES posts(id),
FOREIGN KEY (user_id) REFERENCES users(id)
);
Both inline and table-level foreign key constraints produce the same Drizzle output: a .references(() => table.column) chain on the corresponding column.
Important: references() vs relations()
Drizzle has two distinct APIs for relationships:
.references()— Defines the database-level foreign key constraint. This is what the SQL converter generates. It creates an actual foreign key in the database.relations()— Defines application-level relationships for Drizzle's relational query API. This is separate from the schema definition and is used to enabledb.query.posts.findMany({ with: { author: true } }).
The converter generates .references() because it maps directly from SQL foreign key constraints. You may optionally add relations() definitions afterward for the query API.
Circular References
When two tables reference each other, the converter generates both .references() calls. In TypeScript, you may need to use Drizzle's AnyPgColumn type for circular references:
import { AnyPgColumn } from "drizzle-orm/pg-core";
authorId: integer("author_id").references((): AnyPgColumn => users.id)
Use Case
You have a relational database with foreign key constraints and want to preserve those relationships when converting to Drizzle ORM schema, ensuring referential integrity is maintained at the database level.