Database

Migrations

Version control your database schema with migrations. Create, modify, and rollback changes safely.

Up Migrations

Create tables and modify schema

Down Migrations

Rollback changes safely

Batch System

Track and rollback by batch

Schema Builder

Fluent API for table creation

Creating a Migration

migrations/create_users.ts
1import { Schema, defineMigration } from "canxjs";
2
3defineMigration(
4 "create_users_table",
5
6 // UP: Create the table
7 async () => {
8 await Schema.create("users", (table) => {
9 table.id(); // BIGINT primary key
10 table.string("name"); // VARCHAR(255)
11 table.string("email").unique(); // VARCHAR(255) UNIQUE
12 table.string("password");
13 table.string("role").default("user");
14 table.text("bio").nullable(); // TEXT, can be NULL
15 table.boolean("is_active").default(true);
16 table.timestamps(); // created_at, updated_at
17 });
18 },
19
20 // DOWN: Drop the table
21 async () => {
22 await Schema.drop("users");
23 }
24);

Column Types

MethodSQL Type
id()BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
string(name, len?)VARCHAR(255)
text(name)TEXT
integer(name)INT
boolean(name)TINYINT(1)
datetime(name)DATETIME
json(name)JSON
column-types.ts
1await Schema.create("products", (table) => {
2 table.id(); // BIGINT AUTO_INCREMENT PRIMARY KEY
3 table.string("name", 100); // VARCHAR(100)
4 table.text("description"); // TEXT
5 table.integer("quantity"); // INT
6 table.bigInteger("views"); // BIGINT
7 table.float("weight"); // FLOAT
8 table.decimal("price", 10, 2); // DECIMAL(10,2)
9 table.boolean("is_available"); // TINYINT(1)
10 table.date("release_date"); // DATE
11 table.datetime("published_at"); // DATETIME
12 table.timestamp("verified_at"); // TIMESTAMP
13 table.json("metadata"); // JSON
14 table.binary("thumbnail"); // BLOB
15 table.timestamps(); // created_at, updated_at
16 table.softDeletes(); // deleted_at
17});

Column Modifiers

modifiers.ts
1await Schema.create("posts", (table) => {
2 table.id();
3 table.string("title");
4 table.string("slug").unique(); // Unique constraint
5 table.text("content").nullable(); // Allow NULL values
6 table.string("status").default("draft"); // Default value
7 table.integer("views").unsigned(); // Unsigned integer
8 table.integer("category_id").index(); // Add index
9 table.timestamps();
10});

Foreign Keys

foreign-keys.ts
1await Schema.create("posts", (table) => {
2 table.id();
3 table.string("title");
4 table.text("content");
5
6 // Foreign key with cascade delete
7 table.bigInteger("user_id").unsigned()
8 .references("users", "id")
9 .onDelete("CASCADE");
10
11 table.bigInteger("category_id").unsigned()
12 .references("categories", "id")
13 .onDelete("SET NULL");
14
15 table.timestamps();
16});

Running Migrations

run-migrations.ts
1import { migrator } from "canxjs";
2
3// Run all pending migrations
4await migrator.run();
5
6// Rollback last batch
7await migrator.rollback();
8
9// Reset all migrations (rollback all)
10await migrator.reset();
11
12// Fresh: reset and re-run all
13await migrator.fresh();
14
15// Check migration status
16const status = await migrator.status();
17console.log(status);
18// [{ name: "create_users_table", ran: true }, ...]

CLI Commands

terminal
1# Run pending migrations
2bunx canx migrate
3
4# Rollback last batch
5bunx canx migrate:rollback
6
7# Reset all migrations
8bunx canx migrate:reset
9
10# Fresh migration (reset + run)
11bunx canx migrate:fresh
12
13# Check migration status
14bunx canx migrate:status

Schema Utilities

schema-utils.ts
1// Check if table exists
2const exists = await Schema.hasTable("users");
3
4// Check if column exists
5const hasEmail = await Schema.hasColumn("users", "email");
6
7// Rename table
8await Schema.rename("posts", "articles");
9
10// Drop table if exists
11await Schema.dropIfExists("temp_data");

Next Steps

Learn how to populate your database with test data using seeders.