Migrating from v0.4.x to v0.5.0
Guide for upgrading from v0.4.x to v0.5.0 of Migration Script Runner.
Table of Contents
- Overview
- Prerequisites
- Upgrade Steps
- No Breaking Changes
- New Features (Optional)
- Testing Your Migration
- Common Migration Issues
- Rollback Procedure
- Getting Help
- Summary
Overview
v0.5.0 is a feature release with no breaking changes. All v0.4.x code continues to work without modification. This release adds powerful new features for transaction management and environment variable configuration.
What’s New in v0.5.0
- ✨ Transaction Management - Configurable transactions with automatic retry logic
- ✨ Environment Variables - Complete MSR_* environment variable support
- ✨ Enhanced Hooks - Transaction lifecycle hooks and better hook organization
- 📚 Improved Documentation - Comprehensive API documentation and reorganized structure
Migration Effort
Estimated Time: 5-15 minutes
Complexity: Low - No code changes required, new features are opt-in
Prerequisites
Before upgrading, ensure:
- You’re currently on v0.4.x
- Your tests are passing
- You have a backup of your database
- Your migrations follow the standard naming convention (
V{timestamp}_{description})
Upgrade Steps
1. Update Package
npm install @migration-script-runner/core@^0.5.0
Or with yarn:
yarn upgrade @migration-script-runner/core@^0.5.0
2. Verify Existing Code Works
Your existing v0.4.x code will continue to work without changes:
// v0.4.x code - still works in v0.5.0
import { MigrationScriptExecutor, Config } from '@migration-script-runner/core';
const config = new Config();
config.folder = './migrations';
const executor = new MigrationScriptExecutor(handler, config);
const result = await executor.up();
3. Run Your Test Suite
npm test
All tests should pass without modifications.
4. Optional: Adopt New Features
v0.5.0 adds optional new features you can adopt at your own pace. See sections below for details.
No Breaking Changes
v0.5.0 maintains 100% backward compatibility with v0.4.x:
| Feature | v0.4.x Behavior | v0.5.0 Behavior |
|---|---|---|
| Config class | All properties work | All properties work + new transaction property (optional) |
| IMigrationHooks | All hooks work | All hooks work + new transaction hooks (optional) |
| Database handlers | All interfaces work | All interfaces work + new transaction interfaces (optional) |
| Migration files | All file types supported | All file types supported (no changes) |
| API methods | All methods unchanged | All methods unchanged |
You don’t need to change anything - your v0.4.x code works as-is.
New Features (Optional)
Feature 1: Transaction Management
What it does: Provides fine-grained control over how migrations are wrapped in database transactions, with automatic retry logic for transient failures.
Who needs it:
- Production systems requiring transactional guarantees
- High-concurrency databases with deadlock risks
- Systems needing configurable isolation levels
- NoSQL databases with transaction support
How to adopt:
Basic Usage (SQL Databases)
import { MigrationScriptExecutor, Config, TransactionMode } from '@migration-script-runner/core';
const config = new Config();
// Each migration in its own transaction (default)
config.transaction.mode = TransactionMode.PER_MIGRATION;
// All migrations in single transaction
config.transaction.mode = TransactionMode.PER_BATCH;
// No automatic transactions
config.transaction.mode = TransactionMode.NONE;
const executor = new MigrationScriptExecutor(handler, config);
await executor.up();
Configure Retry Logic
import { IsolationLevel } from '@migration-script-runner/core';
// Handle high-concurrency databases
config.transaction.retries = 10; // More retries
config.transaction.retryDelay = 200; // Longer initial delay
config.transaction.retryBackoff = true; // Exponential backoff
// Maximum consistency (slower, more deadlocks)
config.transaction.isolation = IsolationLevel.SERIALIZABLE;
Implement Transaction Support in Your Handler
For SQL Databases (PostgreSQL, MySQL, etc.):
import { IDatabaseMigrationHandler, ITransactionalDB } from '@migration-script-runner/core';
import { Pool } from 'pg';
interface IPostgresDB extends ITransactionalDB {
query<T>(sql: string, params?: unknown[]): Promise<T[]>;
}
class PostgresDB implements IPostgresDB {
constructor(private pool: Pool) {}
async beginTransaction(): Promise<void> {
await this.pool.query('BEGIN');
}
async commit(): Promise<void> {
await this.pool.query('COMMIT');
}
async rollback(): Promise<void> {
await this.pool.query('ROLLBACK');
}
async setIsolationLevel(level: string): Promise<void> {
await this.pool.query(`SET TRANSACTION ISOLATION LEVEL ${level}`);
}
async query<T>(sql: string, params?: unknown[]): Promise<T[]> {
const result = await this.pool.query(sql, params);
return result.rows as T[];
}
}
For NoSQL Databases (MongoDB, Firestore, DynamoDB):
import { ICallbackTransactionalDB } from '@migration-script-runner/core';
import { MongoClient, ClientSession } from 'mongodb';
interface IMongoDBConnection extends ICallbackTransactionalDB<ClientSession> {
client: MongoClient;
}
class MongoDBConnection implements IMongoDBConnection {
constructor(public client: MongoClient) {}
async runTransaction<T>(
callback: (session: ClientSession) => Promise<T>
): Promise<T> {
const session = this.client.startSession();
try {
return await session.withTransaction(callback);
} finally {
await session.endSession();
}
}
}
If you don’t need transactions:
No changes needed! Your existing IDB implementation continues to work. MSR will skip transaction management if your database doesn’t implement transaction interfaces.
Feature 2: Environment Variable Configuration
What it does: Configure MSR entirely through environment variables, following 12-factor app principles.
Who needs it:
- Docker/Kubernetes deployments
- CI/CD pipelines
- Cloud-native applications
- Multi-environment deployments (dev, staging, production)
How to adopt:
Quick Start
Set environment variables and MSR picks them up automatically:
# Core configuration
export MSR_FOLDER=./database/migrations
export MSR_TABLE_NAME=migration_history
export MSR_DRY_RUN=false
# Validation
export MSR_VALIDATE_BEFORE_RUN=true
export MSR_STRICT_VALIDATION=true
# Transaction management
export MSR_TRANSACTION_MODE=PER_MIGRATION
export MSR_TRANSACTION_ISOLATION=READ_COMMITTED
export MSR_TRANSACTION_RETRIES=5
# Run migrations
node migrate.js
Use ConfigLoader for Waterfall Loading
import { ConfigLoader } from '@migration-script-runner/core';
// Automatic waterfall: env vars → config file → defaults → overrides
const config = ConfigLoader.load({
// Optional programmatic overrides (highest priority)
folder: './migrations'
});
const executor = new MigrationScriptExecutor(handler, config);
await executor.up();
Docker/Kubernetes Example
docker-compose.yml:
version: '3.8'
services:
migrations:
image: my-app-migrations
environment:
MSR_FOLDER: /app/migrations
MSR_TABLE_NAME: schema_version
MSR_TRANSACTION_MODE: PER_BATCH
MSR_TRANSACTION_RETRIES: 10
MSR_VALIDATE_BEFORE_RUN: "true"
MSR_STRICT_VALIDATION: "true"
Kubernetes ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: msr-config
data:
MSR_FOLDER: "/app/migrations"
MSR_TABLE_NAME: "schema_version"
MSR_TRANSACTION_MODE: "PER_MIGRATION"
MSR_TRANSACTION_ISOLATION: "READ_COMMITTED"
MSR_TRANSACTION_RETRIES: "5"
MSR_VALIDATE_BEFORE_RUN: "true"
All Available Environment Variables
See Environment Variables API Reference for complete documentation of all 33 environment variables organized by category.
Feature 3: Transaction Hooks
What it does: Monitor and extend transaction lifecycle with new hooks.
Who needs it:
- Systems requiring transaction metrics
- Applications needing transaction logging
- Monitoring and alerting integrations
How to adopt:
import { IMigrationHooks, ITransactionContext } from '@migration-script-runner/core';
class TransactionMonitoringHooks implements IMigrationHooks {
async beforeTransactionBegin(context: ITransactionContext): Promise<void> {
console.log(`Starting transaction ${context.transactionId} (${context.mode})`);
}
async afterCommit(context: ITransactionContext): Promise<void> {
const duration = Date.now() - context.startTime;
console.log(`Transaction ${context.transactionId} committed in ${duration}ms`);
// Send metrics
metrics.timing('transaction.duration', duration, {
mode: context.mode,
migrations: context.migrations.length,
attempts: context.attempt
});
}
async onCommitRetry(
context: ITransactionContext,
error: Error,
attempt: number
): Promise<void> {
console.warn(`Transaction ${context.transactionId} retry #${attempt}: ${error.message}`);
// Alert on multiple retries
if (attempt >= 3) {
alerting.warn('High transaction retry count', { context, error, attempt });
}
}
async beforeRollback(context: ITransactionContext, error: Error): Promise<void> {
console.error(`Rolling back transaction ${context.transactionId}:`, error);
alerting.error('Transaction rollback', { context, error });
}
}
const executor = new MigrationScriptExecutor(handler, config, {
hooks: new TransactionMonitoringHooks()
});
Testing Your Migration
1. Test in Development
# Set environment variables
export MSR_FOLDER=./test-migrations
export MSR_DRY_RUN=true
# Run with new features
npm start
2. Verify Transaction Behavior
Create a test migration that will fail:
// migrations/V202501010001_test_transaction.ts
export default class TestTransaction {
async up(db: any): Promise<string> {
await db.query('CREATE TABLE test_tx (id INT)');
throw new Error('Test rollback'); // Force rollback
}
}
Run and verify transaction rolls back properly.
3. Test Environment Variables
# Test all core variables work
export MSR_FOLDER=./migrations
export MSR_TABLE_NAME=test_schema
export MSR_VALIDATE_BEFORE_RUN=true
npm start
4. Production Rollout Checklist
- Tested in development environment
- Tested in staging with production-like data
- Verified transaction modes work correctly
- Confirmed environment variables load properly
- Validated hooks are called at expected times
- Checked logs for retry behavior
- Verified backward compatibility with existing migrations
- Database backup created before deployment
Common Migration Issues
Issue 1: Transaction Deadlocks in Production
Symptom: Seeing “deadlock detected” errors frequently
Solution:
// Increase retries and use exponential backoff
config.transaction.retries = 10;
config.transaction.retryDelay = 200;
config.transaction.retryBackoff = true;
// OR use per-migration mode instead of per-batch
config.transaction.mode = TransactionMode.PER_MIGRATION;
// OR lower isolation level (if data consistency allows)
config.transaction.isolation = IsolationLevel.READ_COMMITTED;
Issue 2: Environment Variables Not Loading
Symptom: Configuration not applying from environment variables
Solution:
// Ensure you're using ConfigLoader
import { ConfigLoader } from '@migration-script-runner/core';
const config = ConfigLoader.load(); // This loads env vars automatically
// NOT this (manual Config doesn't load env vars automatically)
const config = new Config(); // ❌ Won't load env vars
Issue 3: Hooks Not Being Called
Symptom: Transaction hooks not executing
Solution:
Ensure your database implements transaction interfaces:
// ✅ Implements ITransactionalDB - hooks will be called
class MyDB implements ITransactionalDB {
async beginTransaction() { /* ... */ }
async commit() { /* ... */ }
async rollback() { /* ... */ }
}
// ❌ Only implements IDB - transaction hooks skipped
class MyDB implements IDB {
// No transaction methods
}
Rollback Procedure
If you need to rollback to v0.4.x:
1. Reinstall v0.4.x
npm install @migration-script-runner/core@^0.4.0
2. Remove New Config Properties (if used)
// Remove v0.5.0 transaction config
delete config.transaction; // Or just remove the line
3. Verify Tests Pass
npm test
Note: Database migrations executed with v0.5.0 are compatible with v0.4.x. Your migration history will work with both versions.
Getting Help
If you encounter issues during migration:
- Check the documentation:
- Search existing issues:
- Ask for help:
- GitHub Discussions
- Create a new issue with the
questionlabel
Summary
v0.5.0 is a smooth, non-breaking upgrade that adds powerful new features:
✅ Zero breaking changes - All v0.4.x code works unchanged ✅ Optional adoption - New features are opt-in ✅ 5-15 minute upgrade - Update package and you’re done ✅ Production ready - 100% test coverage, comprehensive code review
Next steps:
- Update to v0.5.0:
npm install @migration-script-runner/core@^0.5.0 - Run tests to verify compatibility
- Explore new features at your own pace
- Read the CHANGELOG for complete details
Happy migrating! 🚀