Migrations
Manage database schema changes with VibORM migrations
VibORM provides two approaches for managing database schema changes:
- Push - Direct schema synchronization, ideal for development
- Migrate - File-based migrations with version control, ideal for production
Both approaches work by comparing your VibORM schema definitions against the current database state and generating the necessary DDL to synchronize them.
Choose Your Approach
| Push | Migrate | |
|---|---|---|
| Use case | Development, prototyping | Production, team collaboration |
| Version control | No migration files | Yes, SQL files committed to git |
| Rollback | Manual | Supported via down migrations |
| CI/CD | Not recommended | Fully supported |
CLI vs API
VibORM migrations can be used via the CLI or programmatically via the Migration Client API.
CLI
The CLI is the recommended way to manage migrations during development:
# Push schema directly to database
npx viborm push
# Generate a new migration file
npx viborm migrate generate --name add-users
# Apply pending migrations
npx viborm migrate apply
# Check migration status
npx viborm migrate statusMigration Client API
For programmatic control (scripts, CI/CD, custom tooling), use the migration client:
import { createMigrationClient } from "viborm/migrations";
import { createFsStorageDriver } from "viborm/migrations/storage/fs";
import { client } from "./client";
const migrations = createMigrationClient(client, {
storageDriver: createFsStorageDriver("./migrations"),
});
// File-based migration operations (require storage driver)
await migrations.generate({ name: "add-users" });
await migrations.apply();
await migrations.status();
// Push works with or without storage driver
await migrations.push({
resolve: async (change) => {
// Handle destructive or ambiguous changes
if (change.type === "destructive") {
return "proceed"; // or "reject"
}
return "rename"; // or "addAndDrop" or "reject"
},
});Storage Driver Required
File-based operations (generate, apply, status, reset, rollback) require a storage driver. The push() method works without a storage driver since it doesn't use migration files.
Migration Client Options
interface MigrationClientOptions {
/** Storage driver for migration files (required for file-based operations) */
storageDriver?: MigrationStorageDriver;
/** Migration tracking table name (default: _viborm_migrations) */
tableName?: string;
}How It Works
Both push and migrate follow the same core process:
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ VibORM Schema │ ──▶ │ Schema Diff │ ──▶ │ DDL Generation │
│ (your code) │ │ (detect changes)│ │ (database SQL) │
└─────────────────┘ └──────────────────┘ └─────────────────┘- Serialize your VibORM models into a schema snapshot
- Compare against the current database state (push) or previous snapshot (migrate)
- Generate database-specific DDL using the appropriate migration driver
- Execute the DDL (push) or write to a migration file (migrate)
Atomicity
Migrations in VibORM are executed atomically - either all statements succeed or none are applied. This is critical for maintaining database integrity.
VibORM automatically uses the best available method for atomic execution based on your driver:
| Driver Type | Atomicity Method |
|---|---|
| PostgreSQL, MySQL, SQLite | Transaction wrapper |
| D1, D1-HTTP | Native batch() API |
| Neon-HTTP | transaction() function |
| PlanetScale | Transaction wrapper |
All drivers provide atomicity (all-or-nothing) for migrations. Neon-HTTP uses transaction() with full PostgreSQL transaction semantics, providing transaction isolation by default (ReadCommitted) with configurable levels (ReadUncommitted, ReadCommitted, RepeatableRead, Serializable). Only D1 and D1-HTTP use batch execution without isolation guarantees, but this is rarely a concern since migrations typically run in controlled environments.
What Atomicity Means
- If migration succeeds: All schema changes are applied
- If migration fails: No schema changes are applied (rolled back)
- Your database is never left in a partially migrated state
This applies to both push and migrate apply commands.