Core Concepts

Column Types & Modifiers

All available column helpers and the chainable modifiers used to configure them.

This page serves as a reference guide for all available column helpers and the chainable modifiers used to configure them.

Column Types

These functions define the data type of your column.

FunctionSQLite TypeDefault TS TypeModes & Special Usage
text(name, config?)TEXTstringmode: 'json': The column is serialized/deserialized as JSON, and the TS type becomes any.
enum: [...]: Constrains values to a TypeScript union type (e.g., `'active'
integer(name, config?)INTEGERnumbermode: 'timestamp': Treats the value as a UNIX epoch second and maps to a Date object.
mode: 'timestamp_ms': Treats the value as a UNIX epoch millisecond and maps to a Date object.
mode: 'boolean': Maps 0 and 1 to false and true.
real(name)REALnumberUsed for floating-point numbers.
blob(name, config?)BLOBUint8Arraymode: 'json': Stores JSON as a binary blob, maps to any.
mode: 'bigint': Maps the value to a bigint.
boolean(name)BOOLEANbooleanAn alias for integer(name, { mode: 'boolean' }).
numeric(name, config?)NUMERICnumberA flexible type that can store various numeric formats.
mode: 'bigint': Maps the value to a bigint.
enumType(name, vals)TEXTvals[number]A convenient shortcut for text(name, { enum: vals }).

Column Modifiers

These chainable methods add constraints and behaviors to your column definitions.

ModifierDescriptionExample
.primaryKey()Marks the column as the primary key. Automatically implies .notNull().integer('id').primaryKey()
.autoincrement()When used on an integer primary key, makes it auto-incrementing.integer('id').primaryKey().autoincrement()
.notNull()Adds a NOT NULL constraint. Inserts must provide a value for this column unless a default is set.text('email').notNull()
.unique()Adds a UNIQUE constraint, ensuring all values in this column are unique across the table.text('session_token').unique()
.default(value)Provides a static default value for the column if one is not provided on insert.integer('status').default(0)
.$defaultFn(() => value)Provides a dynamic default value, evaluated at the time of insertion. Perfect for timestamps or UUIDs.text('id').$defaultFn(() => crypto.randomUUID())
.$onUpdateFn(() => value)Sets a dynamic value that is evaluated every time a row is updated.integer('updated_at').$onUpdateFn(() => new Date())
.references(() => table._.columns.column, options?)Creates a foreign key via a lazy getter (Drizzle-style). Enables self-references and forward refs. Use table._.columns.id to avoid name clashes.integer('author_id').references(() => users._.columns.id, { onDelete: 'cascade' })
.$type<T>()Advanced: Overrides TypeScript's inferred type for the column. Useful for custom data transformations that the ORM doesn't handle natively.text('metadata').$type<MyCustomMetadataType>()

Important Notes

.default() vs .$defaultFn()

Understanding the difference between these two is crucial:

  • .default(value) → Creates a SQL DEFAULT value clause in the table schema. The value must be a simple literal (number, string, boolean). This is evaluated by SQLite at INSERT time.
  • .$defaultFn(fn) → Calls the function in your application code when you INSERT a row. Use this for complex values like Date objects or crypto.randomUUID().
// ✅ CORRECT
export const users = sqliteTable('users', {
  id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
  status: integer('status').default(0),  // Simple value - OK for .default()
  createdAt: integer('created_at', { mode: 'timestamp' })
    .$defaultFn(() => new Date()),  // Date object - must use $defaultFn()
});

// ❌ WRONG - Will cause SQL syntax error!
export const users = sqliteTable('users', {
  id: text('id').primaryKey()
    .default(crypto.randomUUID())  // ❌ Function call in .default()
    .$defaultFn(() => crypto.randomUUID()),
  createdAt: integer('created_at', { mode: 'timestamp' })
    .default(new Date())  // ❌ Date object in .default()
    .$defaultFn(() => new Date()),
});

Rule of thumb:

  • Simple values (0, 'active', false) → use .default()
  • Complex values (new Date(), crypto.randomUUID(), computed values) → use .$defaultFn()
  • Never use both on the same column

Accessing Columns in Code

When referencing columns in queries, always use the table._.columns.columnName syntax:

// ✅ CORRECT
eq(users._.columns.id, 1)
eq(users._.columns.email, 'john@example.com')
users._.columns.createdAt

// ❌ WRONG - This doesn't work
eq(users.id, 1)
eq(users.email, 'john@example.com')
users.createdAt

The ._ property contains the table's metadata, including all column definitions.

Copyright © 2026