Migrating from v0.6.x to v0.7.0
Guide for upgrading from v0.6.x to v0.7.0 of Migration Script Runner.
Table of Contents
- Overview
- Prerequisites
- Upgrade Steps
- Breaking Changes
- New Features
- Testing After Migration
- Troubleshooting
- API Changes Summary
- Need Help?
- What’s Next?
Overview
v0.7.0 improves adapter ergonomics, code maintainability, and architecture by implementing the Facade and Factory patterns. This release includes two breaking changes: constructor signature change and service property removal.
What’s New in v0.7.0
- 🖥️ CLI Factory - Create command-line interfaces with built-in commands (migrate, list, down, validate, backup) - see CLI Adapter Development Guide
- 🗂️ .env File Support - Automatically load configuration from .env, .env.production, .env.local files with priority control
- 🔨 Breaking Change: Single Parameter Constructor - Config moved from second parameter into
dependencies.config - 🔨 Breaking Change: Service Properties Removed - Internal services no longer exposed as public properties (use public API methods instead)
- 🎨 Facade Pattern - Services grouped into 4 logical facades (core, execution, output, orchestration)
- 🏭 Factory Pattern - Service initialization extracted to
MigrationServicesFactory - 🔧 Protected Facades for Adapters - Adapters can extend executor and access protected service facades
- ✨ Extensible Configuration Loading - New
IConfigLoaderinterface andconfigLoaderoption - 🔧 Generic ConfigLoader - Adapters can extend
ConfigLoader<C>with custom config types - 📦 Better Adapter Ergonomics - Simpler constructor signature and better extensibility
- 🎯 Interface Segregation - New
IExecutorOptions<DB>separates required from optional dependencies - ⚡ Reduced Complexity - Constructor reduced from 142 lines to 23 lines (83% reduction)
Migration Effort
Estimated Time: 15-30 minutes
Complexity: Low-Medium
- Low: Update constructor calls (simple parameter move)
- Medium: Replace direct service access with public API methods (if you were accessing internal services)
Prerequisites
Before upgrading, ensure:
- You’re currently on v0.6.x
- Your tests are passing
- You have TypeScript 4.5+ (for best generic inference)
Upgrade Steps
1. Update Package
npm install @migration-script-runner/core@^0.7.0
Or with yarn:
yarn upgrade @migration-script-runner/core@^0.7.0
2. Update Constructor Calls
REQUIRED: Move config from second parameter into dependencies object:
BEFORE (v0.6.x):
import { MigrationScriptExecutor, Config } from '@migration-script-runner/core';
const handler = new MyDatabaseHandler();
const config = new Config();
// Old: config as second parameter
const executor = new MigrationScriptExecutor<IDB>(
{ handler },
config
);
AFTER (v0.7.0):
import { MigrationScriptExecutor, Config } from '@migration-script-runner/core';
const handler = new MyDatabaseHandler();
const config = new Config();
// New: config inside dependencies object
const executor = new MigrationScriptExecutor<IDB>({
handler,
config
});
Quick Find & Replace:
- Find:
}, config) - Replace:
, config }
Breaking Changes
Constructor Signature Change
Impact: All code creating MigrationScriptExecutor instances
Details: The constructor now takes a single parameter. Config moved from second parameter into dependencies.config.
Before (v0.6.x):
constructor<DB extends IDB>(
dependencies: IMigrationExecutorDependencies<DB>,
config?: Config
)
After (v0.7.0):
constructor<DB extends IDB>(
dependencies: IMigrationExecutorDependencies<DB>
)
Examples:
// Minimal usage (config auto-loaded)
const executor = new MigrationScriptExecutor<IDB>({ handler });
// With explicit config
const executor = new MigrationScriptExecutor<IDB>({
handler,
config: myConfig
});
// With custom logger
const executor = new MigrationScriptExecutor<IDB>({
handler,
config: myConfig,
logger: new FileLogger()
});
// With all options
const executor = new MigrationScriptExecutor<IDB>({
handler,
config: myConfig,
configLoader: new CustomConfigLoader(),
logger: new FileLogger(),
hooks: myHooks
});
Service Property Removal (Facade Pattern)
Impact: Code directly accessing internal service properties
Details: MigrationScriptExecutor no longer exposes internal services as public properties. Services are now grouped into protected facades for better encapsulation and adapter extensibility.
Before (v0.6.x):
const executor = new MigrationScriptExecutor<IDB>({ handler }, config);
// ✅ Public service access (v0.6.x)
const backupPath = await executor.backupService.backup();
const scripts = await executor.migrationScanner.scan();
const results = await executor.validationService.validateAll(scripts, config);
executor.logger.info('Migration complete');
After (v0.7.0):
const executor = new MigrationScriptExecutor<IDB>({ handler, config });
// ❌ Direct service access removed (v0.7.0)
// executor.backupService // Property does not exist
// executor.migrationScanner // Property does not exist
// executor.validationService // Property does not exist
// executor.logger // Property does not exist
// ✅ Use public API methods instead:
const backupPath = await executor.createBackup(); // Public method
await executor.list(); // Public method
await executor.validate(); // Public method
await executor.up(); // Public method
Rationale: This change improves encapsulation and reduces the public API surface. Instead of exposing 11+ internal services, MigrationScriptExecutor now only exposes high-level migration operations.
Migration Strategy:
- Replace direct service access with public API methods:
executor.backupService.backup()→executor.createBackup()executor.backupService.restore()→executor.restoreFromBackup()executor.backupService.deleteBackup()→executor.deleteBackup()executor.migrationScanner.scan()→ Useexecutor.list()or internal logicexecutor.validationService.validateAll()→executor.validate()
- For adapters needing service access, extend MigrationScriptExecutor:
// v0.7.0: Adapters can access protected facades
export class PostgresExecutor<DB extends IDB> extends MigrationScriptExecutor<DB> {
public async customBackup(): Promise<string> {
// Access protected facades
this.output.logger.info('Creating Postgres backup...');
const scripts = await this.core.scanner.scan();
return this.core.backup.backup();
}
public async migrateWithMetrics(): Promise<IMigrationResult<DB>> {
const startTime = Date.now();
// Access protected orchestrators
const result = await this.orchestration.workflow.migrateAll();
const duration = Date.now() - startTime;
this.output.logger.info(`Migration completed in ${duration}ms`);
return result;
}
}
Protected Facades (v0.7.0):
core: Business logic services (scanner, schemaVersion, migration, validation, backup, rollback)execution: Execution services (selector, runner, transactionManager)output: Output services (logger, renderer)orchestration: Orchestrators (workflow, validation, reporting, error, hooks, rollback)
New Features
Extensible Configuration Loading
New in v0.7.0: Database adapters can now provide custom configuration loaders to handle database-specific environment variables.
IConfigLoader Interface
interface IConfigLoader<C extends Config = Config> {
load(overrides?: Partial<C>, options?: ConfigLoaderOptions): C;
applyEnvironmentVariables(config: C): void;
}
Custom ConfigLoader Example
Adapters can extend ConfigLoader to add custom environment variable handling:
import { ConfigLoader, Config } from '@migration-script-runner/core';
class PostgreSqlConfigLoader extends ConfigLoader {
applyEnvironmentVariables(config: Config): void {
// Apply base MSR_* variables
super.applyEnvironmentVariables(config);
// Add POSTGRES_* variables
if (process.env.POSTGRES_HOST) {
(config as any).host = process.env.POSTGRES_HOST;
}
if (process.env.POSTGRES_PORT) {
(config as any).port = parseInt(process.env.POSTGRES_PORT);
}
if (process.env.POSTGRES_DATABASE) {
(config as any).database = process.env.POSTGRES_DATABASE;
}
}
}
// Use custom loader
const executor = new MigrationScriptExecutor<IDB>({
handler: myPostgresHandler,
configLoader: new PostgreSqlConfigLoader()
});
Generic ConfigLoader
New in v0.7.0: ConfigLoader is now generic, allowing adapters to extend it with custom configuration types:
class ConfigLoader<C extends Config = Config> implements IConfigLoader<C> {
load(overrides?: Partial<C>, options?: ConfigLoaderOptions): C { ... }
applyEnvironmentVariables(config: C): void { ... }
}
This enables type-safe configuration loading for adapter-specific config properties.
IExecutorOptions Interface
New in v0.7.0: Separates optional dependencies for cleaner interface design:
interface IExecutorOptions<DB extends IDB> {
config?: Config;
configLoader?: IConfigLoader;
logger?: ILogger;
hooks?: IMigrationHooks<DB>;
backupService?: IBackupService;
schemaVersionService?: ISchemaVersionService<DB>;
migrationRenderer?: IMigrationRenderer<DB>;
renderStrategy?: IRenderStrategy<DB>;
migrationService?: IMigrationService<DB>;
migrationScanner?: IMigrationScanner<DB>;
validationService?: IMigrationValidationService<DB>;
metricsCollectors?: IMetricsCollector[];
rollbackService?: IRollbackService<DB>;
loaderRegistry?: ILoaderRegistry<DB>;
}
interface IMigrationExecutorDependencies<DB extends IDB> extends IExecutorOptions<DB> {
handler: IDatabaseMigrationHandler<DB>; // Required
configLoader?: IConfigLoader; // Optional (v0.7.0)
}
This makes it easier for adapters to work with optional services while keeping handler as the only required dependency.
Testing After Migration
After updating your code, verify:
- Build succeeds:
npm run buildortsc - Tests pass:
npm test - Migrations run: Test your migration execution
- Config loading works: Verify environment variables are applied correctly
Quick Validation
// Test that constructor works with new signature
const executor = new MigrationScriptExecutor<IDB>({
handler: myHandler,
config: new Config()
});
// Verify config is loaded
console.log(executor['config'].folder); // Should print configured folder
// Test auto-loading (config not provided)
const autoExecutor = new MigrationScriptExecutor<IDB>({
handler: myHandler
});
console.log(autoExecutor['config']); // Should have auto-loaded config
Troubleshooting
TypeScript Error: “Expected 1 arguments, but got 2”
Cause: You’re still using the old v0.6.x constructor signature.
Fix: Move config from second parameter into dependencies object:
// ❌ Old (v0.6.x)
new MigrationScriptExecutor({ handler }, config)
// ✅ New (v0.7.0)
new MigrationScriptExecutor({ handler, config })
ConfigLoader Methods Not Found
Cause: Trying to use ConfigLoader.load() as a static method.
Fix: Use instance methods instead:
// ❌ Old (v0.6.x)
const config = ConfigLoader.load();
// ✅ New (v0.7.0)
const loader = new ConfigLoader();
const config = loader.load();
Custom Config Not Applied
Cause: Config not passed correctly in dependencies object.
Fix: Ensure config is passed as config property:
// ✅ Correct
new MigrationScriptExecutor({
handler,
config: myConfig // Must be named 'config'
})
Property ‘backupService’ does not exist on type ‘MigrationScriptExecutor’
Cause: Trying to access internal service properties that were removed in v0.7.0.
Fix: Use public API methods or extend the executor:
// ❌ Old (v0.6.x)
const backupPath = await executor.backupService.backup();
await executor.migrationScanner.scan();
// ✅ New (v0.7.0) - Use public API
const backupPath = await executor.createBackup();
await executor.list();
// ✅ Or extend for adapter-specific needs
class CustomExecutor extends MigrationScriptExecutor {
async customBackup() {
return this.core.backup.backup(); // Protected access
}
}
API Changes Summary
| Change | v0.6.x | v0.7.0 | Breaking? |
|---|---|---|---|
| Constructor Parameters | (dependencies, config?) | (dependencies) | ✅ Yes |
| Config Location | Second parameter | Inside dependencies | ✅ Yes |
| Service Properties | Public (11+ properties) | Removed | ✅ Yes |
| Service Access | executor.backupService, executor.migrationScanner, etc. | Use public methods or extend executor | ✅ Yes |
| Facade Pattern | N/A | 4 protected facades | No (internal) |
| Factory Pattern | N/A | MigrationServicesFactory | No (internal) |
| executeBeforeMigrate | Executor method | MigrationWorkflowOrchestrator | No (internal) |
| ConfigLoader Methods | Static | Instance | ⚠️ Minor |
| ConfigLoader Generic | Not generic | ConfigLoader<C> | No |
| IConfigLoader Interface | N/A | New | No |
| IExecutorOptions Interface | N/A | New | No |
| configLoader Option | N/A | New | No |
Need Help?
- 📖 Documentation: Migration Script Runner Docs
- 🐛 Issues: GitHub Issues
- 💬 Discussions: GitHub Discussions
What’s Next?
After successfully migrating to v0.7.0, you can:
- Explore configLoader: Create custom configuration loaders for your database adapter
- Simplify your code: Remove any config-passing boilerplate
- Build adapters: Use the improved ergonomics to build database-specific adapters
- Stay updated: Watch the repository for v0.8.0 announcements