Documentation Index
Fetch the complete documentation index at: https://mintlify.com/kysely-org/kysely/llms.txt
Use this file to discover all available pages before exploring further.
Kysely provides a powerful CreateTableBuilder API for defining database tables. Access it through db.schema.createTable().
Basic Table Creation
Create a simple table with columns:
await db.schema
.createTable('person')
.addColumn('id', 'integer', (col) => col.primaryKey())
.addColumn('first_name', 'varchar(50)', (col) => col.notNull())
.addColumn('last_name', 'varchar(255)')
.addColumn('email', 'varchar(255)', (col) => col.unique())
.execute()
Column Types and Constraints
Common Data Types
Kysely supports standard SQL data types:
await db.schema
.createTable('product')
.addColumn('id', 'integer', (col) => col.autoIncrement().primaryKey())
.addColumn('name', 'varchar(255)', (col) => col.notNull())
.addColumn('description', 'text')
.addColumn('price', 'numeric(8, 2)', (col) => col.notNull())
.addColumn('stock', 'integer', (col) => col.defaultTo(0))
.addColumn('is_active', 'boolean', (col) => col.defaultTo(true))
.addColumn('created_at', 'timestamp', (col) => col.defaultTo(sql`CURRENT_TIMESTAMP`))
.execute()
For dialect-specific types, use the sql tag:
import { sql } from 'kysely'
await db.schema
.createTable('document')
.addColumn('id', 'integer', (col) => col.primaryKey())
.addColumn('metadata', sql`jsonb`)
.execute()
Column Constraints
The column builder provides these constraint methods:
primaryKey() - Mark as primary key
notNull() - Disallow NULL values
unique() - Ensure uniqueness
defaultTo(value) - Set default value
unsigned() - Unsigned integers (MySQL)
autoIncrement() - Auto-incrementing (MySQL, SQLite)
check(expression) - Add check constraint
Auto-Incrementing IDs
Different databases use different approaches:
MySQL/SQLite:
await db.schema
.createTable('person')
.addColumn('id', 'integer', (col) => col.autoIncrement().primaryKey())
.execute()
PostgreSQL (serial):
await db.schema
.createTable('person')
.addColumn('id', 'serial', (col) => col.primaryKey())
.execute()
PostgreSQL (identity):
await db.schema
.createTable('person')
.addColumn('id', 'integer', (col) =>
col.generatedAlwaysAsIdentity().primaryKey()
)
.execute()
MS SQL Server:
await db.schema
.createTable('person')
.addColumn('id', 'integer', (col) => col.identity().primaryKey())
.execute()
Foreign Keys
Column-Level Foreign Keys
Add foreign key constraints directly to columns:
await db.schema
.createTable('pet')
.addColumn('id', 'integer', (col) => col.primaryKey())
.addColumn('name', 'varchar(255)', (col) => col.notNull())
.addColumn('owner_id', 'integer', (col) =>
col.references('person.id').onDelete('cascade')
)
.execute()
Table-Level Foreign Keys
Some databases (like older MySQL versions) require table-level constraints:
await db.schema
.createTable('pet')
.addColumn('id', 'integer', (col) => col.primaryKey())
.addColumn('owner_id', 'integer')
.addForeignKeyConstraint(
'pet_owner_fk',
['owner_id'],
'person',
['id'],
(cb) => cb.onDelete('cascade').onUpdate('cascade')
)
.execute()
Composite Foreign Keys
await db.schema
.createTable('order_item')
.addColumn('order_id', 'integer')
.addColumn('product_id', 'integer')
.addColumn('quantity', 'integer')
.addForeignKeyConstraint(
'order_item_order_fk',
['order_id', 'product_id'],
'order',
['id', 'product_id']
)
.execute()
Table Constraints
Primary Key Constraints
Define composite primary keys:
await db.schema
.createTable('user_role')
.addColumn('user_id', 'integer')
.addColumn('role_id', 'integer')
.addPrimaryKeyConstraint('user_role_pk', ['user_id', 'role_id'])
.execute()
Unique Constraints
await db.schema
.createTable('person')
.addColumn('id', 'integer', (col) => col.primaryKey())
.addColumn('first_name', 'varchar(64)')
.addColumn('last_name', 'varchar(64)')
.addUniqueConstraint('person_name_unique', ['first_name', 'last_name'])
.execute()
On PostgreSQL, specify nulls not distinct:
await db.schema
.createTable('person')
.addColumn('email', 'varchar(255)')
.addUniqueConstraint(
'person_email_unique',
['email'],
(cb) => cb.nullsNotDistinct()
)
.execute()
Check Constraints
import { sql } from 'kysely'
await db.schema
.createTable('product')
.addColumn('price', 'numeric(8, 2)')
.addColumn('discount_price', 'numeric(8, 2)')
.addCheckConstraint(
'price_check',
sql`price > 0 and discount_price <= price`
)
.execute()
Generated Columns
Virtual Generated Columns
import { sql } from 'kysely'
await db.schema
.createTable('person')
.addColumn('first_name', 'varchar(50)')
.addColumn('last_name', 'varchar(50)')
.addColumn('full_name', 'varchar(101)', (col) =>
col.generatedAlwaysAs(sql`concat(first_name, ' ', last_name)`)
)
.execute()
Stored Generated Columns
await db.schema
.createTable('person')
.addColumn('first_name', 'varchar(50)')
.addColumn('last_name', 'varchar(50)')
.addColumn('full_name', 'varchar(101)', (col) =>
col.generatedAlwaysAs(sql`concat(first_name, ' ', last_name)`).stored()
)
.execute()
Special Table Types
Temporary Tables
await db.schema
.createTable('temp_results')
.temporary()
.addColumn('id', 'integer')
.addColumn('value', 'varchar(255)')
.execute()
On PostgreSQL, control commit behavior:
await db.schema
.createTable('temp_results')
.temporary()
.onCommit('drop')
.addColumn('id', 'integer')
.execute()
Conditional Creation
await db.schema
.createTable('person')
.ifNotExists()
.addColumn('id', 'integer', (col) => col.primaryKey())
.addColumn('name', 'varchar(255)')
.execute()
Create Table From SELECT
await db.schema
.createTable('person_backup')
.as(db.selectFrom('person').selectAll())
.execute()
Advanced Modifiers
Front Modifiers
Add SQL after the create keyword:
import { sql } from 'kysely'
await db.schema
.createTable('person')
.modifyFront(sql`global temporary`)
.addColumn('id', 'integer', (col) => col.primaryKey())
.execute()
End Modifiers
Add SQL to the end of the statement:
await db.schema
.createTable('person')
.addColumn('id', 'integer', (col) => col.primaryKey())
.addColumn('name', 'varchar(255)')
.modifyEnd(sql`engine=InnoDB default charset=utf8mb4`)
.execute()
Reusable Patterns
Create reusable column definitions:
import { type CreateTableBuilder, sql } from 'kysely'
const withTimestamps = (builder: CreateTableBuilder<any, any>) => {
return builder
.addColumn('created_at', 'timestamp', (col) =>
col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`)
)
.addColumn('updated_at', 'timestamp', (col) =>
col.notNull().defaultTo(sql`CURRENT_TIMESTAMP`)
)
}
await db.schema
.createTable('person')
.addColumn('id', 'integer', (col) => col.primaryKey())
.addColumn('name', 'varchar(255)', (col) => col.notNull())
.$call(withTimestamps)
.execute()