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.

Relations

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:

  1. .references() — Defines the database-level foreign key constraint. This is what the SQL converter generates. It creates an actual foreign key in the database.

  2. relations() — Defines application-level relationships for Drizzle's relational query API. This is separate from the schema definition and is used to enable db.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.

Try It — SQL to Drizzle Schema

Open full tool