Schema Builder API Reference
The schema builder generates DDL SQL inside migration files. Import Schema and TMigration from @orphnet/d1-eloquent/cli. The up and down functions receive a Schema instance — no db argument, no exec call needed. SQL execution is handled by the CLI.
import type { TMigration } from '@orphnet/d1-eloquent/cli'
import { Schema } from '@orphnet/d1-eloquent/cli'Schema methods
schema.createTable(name, callback)
Creates a new table. Passes a TableBuilder to the callback for defining columns, constraints, and indexes.
schema.createTable('posts', (t) => {
t.id()
t.text('title')
t.timestamps()
})
// CREATE TABLE IF NOT EXISTS posts (id TEXT NOT NULL PRIMARY KEY, ...)schema.dropTable(name)
Drops a table.
schema.dropTable('posts')
// DROP TABLE IF EXISTS postsschema.table(name, callback)
Alters an existing table. Use t.addText() or t.addInteger() inside the callback to add columns.
schema.table('posts', (t) => {
t.addText('slug', { nullable: true })
})
// ALTER TABLE posts ADD COLUMN slug TEXTschema.raw(sql)
Appends a raw SQL statement as-is.
schema.raw('CREATE INDEX idx_posts_slug ON posts (slug)')TableBuilder — create mode
Methods available inside schema.createTable() callbacks.
t.id(name?)
Adds a TEXT NOT NULL PRIMARY KEY column. Defaults to "id".
t.id() // id TEXT NOT NULL PRIMARY KEY
t.id('uuid') // uuid TEXT NOT NULL PRIMARY KEYt.text(name, opts?)
t.text(name: string, opts?: {
nullable?: boolean // default: false
unique?: boolean // default: false
default?: string
}): thist.text('title')
t.text('email', { unique: true })
t.text('status', { default: 'draft' })
t.text('bio', { nullable: true })t.integer(name, opts?)
t.integer(name: string, opts?: {
nullable?: boolean
unique?: boolean
default?: number
}): thist.integer('score')
t.integer('view_count', { default: 0 })t.boolean(name, opts?)
Stored as INTEGER (0 / 1).
t.boolean(name: string, opts?: {
nullable?: boolean
default?: boolean
}): thist.boolean('is_active', { default: true })t.timestamps()
Adds created_at TEXT NOT NULL and updated_at TEXT NOT NULL.
t.timestamps()t.softDeletes(opts?)
Adds a nullable deleted_at TEXT column and (by default) an index on it.
t.softDeletes(opts?: {
column?: string // default: 'deleted_at'
index?: boolean // default: true
indexName?: string
}): thist.softDeletes() // deleted_at TEXT + index
t.softDeletes({ index: false }) // deleted_at TEXT, no index
t.softDeletes({ column: 'removed_at' }) // custom column namet.primary(name)
Adds a PRIMARY KEY table constraint — use for composite primary keys.
t.primary('user_id, role_id')
// PRIMARY KEY (user_id, role_id)t.unique(name, indexName?)
Creates a CREATE UNIQUE INDEX statement after the table definition. Auto-names as uidx_<table>_<col> if indexName is omitted.
t.unique('email')
// CREATE UNIQUE INDEX uidx_users_email ON users (email)t.index(name, indexName?)
Creates a CREATE INDEX statement after the table definition. Auto-names as idx_<table>_<col>.
t.index('user_id')
// CREATE INDEX idx_posts_user_id ON posts (user_id)TableBuilder — alter mode
Methods available inside schema.table() callbacks.
t.addText(name, opts?)
t.addText(name: string, opts?: {
nullable?: boolean
default?: string
}): thisschema.table('posts', (t) => {
t.addText('slug', { nullable: true })
})
// ALTER TABLE posts ADD COLUMN slug TEXTt.addInteger(name, opts?)
t.addInteger(name: string, opts?: {
nullable?: boolean
default?: number
}): thisschema.table('posts', (t) => {
t.addInteger('view_count', { default: 0 })
})
// ALTER TABLE posts ADD COLUMN view_count INTEGER NOT NULL DEFAULT 0t.dropSoftDeletes(column?)
Emits a SQL comment. SQLite/D1 does not support DROP COLUMN safely — dropping deleted_at requires a table rebuild. Use this as a no-op placeholder in down().
schema.table('posts', (t) => {
t.dropSoftDeletes()
})
// -- NOTE: cannot DROP COLUMN deleted_at in SQLite/D1 safelyComplete migration example
// src/database/migrations/20260301000000_create_posts_table.ts
import type { TMigration } from '@orphnet/d1-eloquent/cli'
import { Schema } from '@orphnet/d1-eloquent/cli'
const migration: TMigration = {
name: '20260301000000_create_posts_table',
up: (schema: Schema) => {
schema.createTable('posts', (t) => {
t.id()
t.text('user_id')
t.text('title')
t.text('status', { default: 'draft' })
t.text('body', { nullable: true })
t.softDeletes()
t.timestamps()
t.index('user_id')
})
},
down: (schema: Schema) => {
schema.dropTable('posts')
},
}
export default migrationAdding a column later
// src/database/migrations/20260315000000_add_view_count_to_posts.ts
import type { TMigration } from '@orphnet/d1-eloquent/cli'
import { Schema } from '@orphnet/d1-eloquent/cli'
const migration: TMigration = {
name: '20260315000000_add_view_count_to_posts',
up: (schema: Schema) => {
schema.table('posts', (t) => {
t.addInteger('view_count', { default: 0 })
})
},
down: (schema: Schema) => {
// SQLite does not support DROP COLUMN — no-op
},
}
export default migration