A modern, fast database migration library built for Bun.
- 🚀 Fast: Built with Bun for maximum performance
- 🔒 Type-safe: Full TypeScript support with strict type checking
- 🗄️ Database agnostic: Support for multiple database engines
- 📝 Migration tracking: Automatic migration state management
- 🔄 Rollback support: Easy rollback to previous versions
- ⚙️ Config file: Zero-flag workflow via
latter.config.ts/latter.json - 🧪 Testing friendly: Built-in testing utilities
bun add @jaggler3/latterimport { Latter, Migration } from 'latter';
// Create a migration
const migration = new Migration({
name: 'create_users_table',
up: `
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
`,
down: 'DROP TABLE users;'
});
// Initialize and run migrations
const latter = new Latter({
database: 'sqlite:./app.db', // or 'postgresql://user:pass@localhost/db' or 'mysql://user:pass@localhost/db'
migrationsDir: './migrations'
});
await latter.migrate();Latter supports multiple database engines out of the box:
const latter = new Latter({
database: 'sqlite:./app.db',
migrationsDir: './migrations'
});const latter = new Latter({
database: 'postgresql://username:password@localhost:5432/database',
migrationsDir: './migrations'
});const latter = new Latter({
database: 'mysql://username:password@localhost:3306/database',
migrationsDir: './migrations'
});class Migration {
constructor(options: {
name: string;
up: string;
down: string;
dependencies?: string[];
});
}class Latter {
constructor(options: {
database: string;
migrationsDir: string;
tableName?: string;
});
async migrate(): Promise<void>;
async rollback(steps?: number): Promise<void>;
async status(): Promise<MigrationStatus[]>;
}Latter comes with a powerful command-line interface for managing migrations.
Instead of passing flags on every command, create a latter.config.ts (or latter.config.js / latter.json) in your project root:
// latter.config.ts
import type { LatterConfig } from 'latter';
const config: LatterConfig = {
database: 'sqlite:./app.db', // connection string
migrationsDir: './migrations',
// tableName: 'latter_migrations', // optional
};
export default config;Configuration is resolved in this priority order:
- CLI flags —
--database,--migrations-dir, … - Environment variable —
LATTER_DATABASE_URL - Config file —
latter.config.ts(searched from cwd upward)
# Initialize a new project — generates latter.config.ts + sample migration
latter init
latter init --database sqlite:./app.db
# With a config file in place, no flags needed:
latter migrate
latter status
latter rollback 2
latter create add_users_table
# Override config values on the fly:
latter migrate --database postgres://localhost/prod
latter migrate --migrations-dir ./other-migrations
# Dry run (show what would happen without executing)
latter migrate --dry-run
# Verbose output
latter migrate --verbose
# Advanced sync commands
latter sync
latter migrate --force-sync
latter migrate --skip-out-of-sync
latter mark-applied 001_initial_setup
# Show help
latter --help# Run all tests
bun test
# Run specific test files
bun test src/test/adapters.test.ts
bun test src/test/cli.test.ts# Build the project
bun run build
# Build and watch for changes
bun run build:watchThis project uses GitHub Actions for continuous integration:
- Tests: Runs on every push and pull request across multiple Node.js and Bun versions
- Cross-platform: Tests on Ubuntu, Windows, and macOS with proper shell handling
- Quick feedback: Fast test runs for immediate feedback
- Comprehensive coverage: Matrix testing for thorough validation
- Platform-specific commands: Uses appropriate shells (bash for Unix, PowerShell for Windows)
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
MIT