packages/database/src/schema/ and define both database structure and TypeScript types in a single source of truth.
Schema Overview
Each table is defined in its own file. Relations between tables are centralized inindex.ts.
How a Schema File Works
Here is theusers table as a reference for the patterns used throughout the codebase:
- CUID2 primary keys generated with
$defaultFn(() => createId()) - SQLite column modes for booleans (
{ mode: "boolean" }), timestamps ({ mode: "timestamp" }), and JSON ({ mode: "json" }) - Typed JSON columns with
.$type<YourInterface>() - Soft deletes via a
deletedAtcolumn - Automatic timestamps with
$defaultFnand$onUpdateFn - Exported types for both select (
User) and insert (NewUser)
Adding New Tables
1
Create the schema file
Create a new file in
packages/database/src/schema/:2
Define relations
Add relations to If widgets should appear in organization queries, add a reverse relation to the existing
packages/database/src/schema/index.ts:organizationsRelations:3
Export the schema
Add the exports to the bottom of
packages/database/src/schema/index.ts:4
Generate and apply the migration
Adding Columns to Existing Tables
To add a column to an existing table, edit the table’s schema file directly and then generate a migration. For example, adding abio field to the users table:
Column Types
SQLite has a limited type system. Drizzle maps TypeScript types to SQLite storage using column modes.Text Columns
Integer Columns
Default Values
Indexes and Constraints
Indexes
Define indexes in the third argument tosqliteTable:
Unique Constraints
Foreign Keys
Migrations Workflow
BunShip uses Drizzle Kit for migrations. The workflow is:- Edit schema files in
packages/database/src/schema/ - Generate a migration SQL file
- Apply the migration to your database
Generate a Migration
migrations/ directory.
Apply Migrations
DATABASE_URL.
Push (Development Shortcut)
During development, you can push schema changes directly without generating migration files:Inspect Your Database
Open Drizzle Studio to browse your data:https://local.drizzle.studio where you can view tables, run queries, and inspect data.
Relations and Joins
Drizzle supports relational queries through therelations() function, which enables nested data fetching without writing manual joins.
Defining Relations
Querying with Relations
Once relations are defined, usedb.query to fetch nested data:
Manual Joins
For more control, use Drizzle’s SQL-like query builder:Next Steps
Adding Routes
Build API endpoints that use your new tables
Email Templates
Send notifications for your new resources

