Environment Variables Guide
Complete guide to configuring Migration Script Runner using environment variables
Table of contents
- Overview
- Configuration Loading (Waterfall)
- Type-Safe Environment Variables
- Quick Start
- .env File Support (v0.7.0+)
- Environment Variables
- Configuration Files
- Platform-Specific Examples
- Environment-Specific Strategies
- Advanced Configuration
- Troubleshooting
- Complete Example
- Reference
- Next Steps
Overview
MSR v0.5.0+ supports configuration through environment variables, following 12-Factor App principles. This enables:
- Environment-specific configuration without code changes
- Container-friendly deployment (Docker, Kubernetes)
- CI/CD integration with secrets management
- Production-ready practices for configuration management
- .env file support (v0.7.0+) for local development and environment-specific overrides
Configuration Loading (Waterfall)
MSR loads configuration using a waterfall approach with clear priority:
1. Built-in defaults (lowest priority)
↓
2. Config file (msr.config.js/json)
↓
3. .env files (.env.local, .env, env) - v0.7.0+
↓
4. Environment variables (MSR_*)
↓
5. Constructor overrides (highest priority)
Each level overrides the previous one, allowing flexible configuration strategies.
.env files (v0.7.0+): MSR automatically loads .env files using
config.envFileSources. Files are loaded in priority order (first file wins). By default:['.env.local', '.env', 'env'].
Type-Safe Environment Variables
MSR provides organized enums for type-safe access to environment variable names. Variables are grouped by category (Core, Validation, Logging, Backup, Transaction) with a unified EnvironmentVariables type combining all categories. This is used internally by ConfigLoader and is available for your use:
import { EnvironmentVariables as ENV } from '@migration-script-runner/core';
// Type-safe access to environment variables
const folder = process.env[ENV.MSR_FOLDER];
const dryRun = process.env[ENV.MSR_DRY_RUN];
const tableName = process.env[ENV.MSR_TABLE_NAME];
// Auto-completion and compile-time checking
if (process.env[ENV.MSR_LOGGING_ENABLED] === 'true') {
console.log(`Logging to: ${process.env[ENV.MSR_LOGGING_PATH]}`);
}
Benefits:
- Auto-completion - Your IDE will suggest all available environment variable names
- Compile-time checking - Typos are caught at build time, not runtime
- Refactoring support - Rename safely across your entire codebase
- Single source of truth - All environment variable names defined in one place
See Also:
- Environment Variables API Reference - Complete reference with detailed descriptions for all MSR_* variables
- EnvironmentVariables Source - Type union and enum definitions with JSDoc comments
Quick Start
Basic Setup
1. No configuration needed - works out of the box:
import { MigrationScriptExecutor } from '@migration-script-runner/core';
import { MyDatabaseHandler } from './database-handler';
const handler = new MyDatabaseHandler();
const executor = new MigrationScriptExecutor({ handler });
await executor.up();
2. Use environment variables for deployment:
# Set environment variables
export MSR_FOLDER=./database/migrations
export MSR_TABLE_NAME=migration_history
export MSR_LOGGING_ENABLED=true
export MSR_LOGGING_PATH=./logs
# Run your application
npm start
3. Override when needed:
// Env vars are loaded automatically, but you can override
const executor = new MigrationScriptExecutor({ handler }, {
dryRun: true // Override for this specific run
});
.env File Support (v0.7.0+)
MSR automatically loads environment variables from .env files using the config.envFileSources property. This is perfect for:
- Local development - Keep credentials out of version control
- Environment-specific configuration - Use
.env.production,.env.development, etc. - Quick configuration - Simple key=value format without code changes
- Team consistency - Share configuration templates via
.env.example
Default Behavior
By default, MSR looks for these files (in priority order):
config.envFileSources = ['.env.local', '.env', 'env'];
Priority: First file takes precedence. If .env.local exists, values from .env are only used when not defined in .env.local.
Basic Example
Create a .env file in your project root:
# .env
MSR_FOLDER=./database/migrations
MSR_TABLE_NAME=migration_history
MSR_DRY_RUN=false
MSR_LOG_LEVEL=info
That’s it! MSR will automatically load these values:
const executor = new MigrationScriptExecutor({ handler });
// Configuration loaded from .env automatically
Environment-Specific Files
Development Setup
# .env.development
MSR_FOLDER=./migrations
MSR_LOG_LEVEL=debug
MSR_DRY_RUN=true
const config = new Config();
config.envFileSources = ['.env.development', '.env'];
Production Setup
# .env.production
MSR_FOLDER=/app/migrations
MSR_LOG_LEVEL=error
MSR_DRY_RUN=false
MSR_ROLLBACK_STRATEGY=BACKUP
const config = new Config();
config.envFileSources = ['.env.production', '.env'];
Local Overrides
Use .env.local for personal overrides (add to .gitignore):
# .env.local (not in version control)
MSR_FOLDER=./my-local-migrations
MSR_LOG_LEVEL=debug
// Default behavior - automatically uses .env.local if it exists
const config = new Config();
// config.envFileSources = ['.env.local', '.env', 'env'] (default)
Custom File Names
const config = new Config();
config.envFileSources = ['database.env', 'secrets.env'];
Disable .env Loading
To use only system environment variables:
const config = new Config();
config.envFileSources = []; // Disable .env file loading
File Format
.env files use simple KEY=VALUE format:
# Comments are supported
MSR_FOLDER=./migrations
MSR_TABLE_NAME=schema_version
# Quotes are optional for strings
MSR_LOG_LEVEL=info
# Booleans
MSR_DRY_RUN=false
# Numbers
MSR_DISPLAY_LIMIT=10
# Nested properties (dot notation)
MSR_BACKUP_FOLDER=./backups
MSR_BACKUP_DELETE_BACKUP=true
MSR_BACKUP_TIMESTAMP=true
Best Practices
- Version control - Commit
.env.examplewith dummy values, ignore.envand.env.local - Documentation - Document all env vars in
.env.example - Validation - Check required vars at startup
- Security - Never commit real credentials
- Consistency - Use same file names across environments
# .env.example (commit this)
MSR_FOLDER=./migrations
MSR_TABLE_NAME=schema_version
MSR_LOG_LEVEL=info
# Add your database credentials here
# .gitignore
.env
.env.local
.env.*.local
Environment Variables
Simple Properties
Configure basic settings with MSR_* environment variables:
# Migration folder
export MSR_FOLDER=./database/migrations
# Tracking table name
export MSR_TABLE_NAME=migration_history
# Before migrate hook name
export MSR_BEFORE_MIGRATE_NAME=beforeMigrate
# Display limit (0 = show all)
export MSR_DISPLAY_LIMIT=20
# Boolean flags
export MSR_DRY_RUN=true
export MSR_RECURSIVE=true
export MSR_VALIDATE_BEFORE_RUN=true
export MSR_STRICT_VALIDATION=false
export MSR_SHOW_BANNER=false
# Log level (error, warn, info, debug)
export MSR_LOG_LEVEL=info
Boolean values are case-insensitive:
true,1,yes,on→true- Everything else →
false
Log levels (in order of verbosity):
error- Only errors (production)warn- Warnings + errorsinfo- Normal operation (default)debug- All logs including debug output
Complex Objects (Dot-Notation)
Configure nested objects using dot-notation (recommended):
Logging Configuration
export MSR_LOGGING_ENABLED=true
export MSR_LOGGING_PATH=./logs/migrations
export MSR_LOGGING_MAX_FILES=30
export MSR_LOGGING_TIMESTAMP_FORMAT=YYYY-MM-DD
export MSR_LOGGING_LOG_SUCCESSFUL=true
Backup Configuration
export MSR_BACKUP_FOLDER=./backups
export MSR_BACKUP_TIMESTAMP=true
export MSR_BACKUP_DELETE_BACKUP=true
export MSR_BACKUP_PREFIX=db-backup
export MSR_BACKUP_TIMESTAMP_FORMAT=YYYY-MM-DD-HH-mm-ss
Transaction Configuration
export MSR_TRANSACTION_MODE=PER_MIGRATION # or PER_BATCH, NONE
export MSR_TRANSACTION_ISOLATION=READ_COMMITTED # or READ_UNCOMMITTED, REPEATABLE_READ, SERIALIZABLE
export MSR_TRANSACTION_TIMEOUT=30000 # milliseconds
export MSR_TRANSACTION_RETRIES=3 # number of retry attempts
export MSR_TRANSACTION_RETRY_DELAY=100 # milliseconds
export MSR_TRANSACTION_RETRY_BACKOFF=true # exponential backoff
Naming Convention:
MSR_prefix for all variables- Nested properties use
_separator - camelCase property names converted to SNAKE_CASE
- Example:
config.logging.maxFiles→MSR_LOGGING_MAX_FILES
Complex Objects (JSON)
Alternatively, use JSON for complex configuration:
# Logging as JSON
export MSR_LOGGING='{"enabled":true,"path":"./logs","maxFiles":30}'
# Backup as JSON
export MSR_BACKUP='{"folder":"./backups","timestamp":true,"deleteBackup":true}'
# Transaction as JSON
export MSR_TRANSACTION='{"mode":"PER_MIGRATION","isolation":"READ_COMMITTED","retries":3}'
Note: Dot-notation variables take precedence over JSON if both are set.
File Patterns
Configure migration file patterns using JSON array:
# Single pattern
export MSR_FILE_PATTERNS='["^V(\\d+)_.*\\.ts$"]'
# Multiple patterns (TypeScript and SQL)
export MSR_FILE_PATTERNS='["^V(\\d+)_.*\\.ts$","^V(\\d+)_.*\\.sql$"]'
Configuration Files
JavaScript Config (Recommended)
Create msr.config.js in your project root:
// msr.config.js
module.exports = {
folder: './database/migrations',
tableName: 'migration_history',
displayLimit: 20,
recursive: true,
// Can use process.env for dynamic values
validateBeforeRun: true,
strictValidation: process.env.CI === 'true',
logging: {
enabled: true,
path: './logs/migrations',
maxFiles: 30,
timestampFormat: 'YYYY-MM-DD'
},
backup: {
folder: './backups',
timestamp: true,
deleteBackup: true,
prefix: 'db-backup',
timestampFormat: 'YYYY-MM-DD-HH-mm-ss'
}
};
JSON Config
Create msr.config.json for static configuration:
{
"folder": "./database/migrations",
"tableName": "migration_history",
"displayLimit": 20,
"recursive": true,
"validateBeforeRun": true,
"strictValidation": false,
"logging": {
"enabled": true,
"path": "./logs/migrations",
"maxFiles": 30
},
"backup": {
"folder": "./backups",
"timestamp": true,
"deleteBackup": true,
"prefix": "db-backup"
}
}
Custom Config File Location
Use MSR_CONFIG_FILE to specify a custom location:
export MSR_CONFIG_FILE=./config/production.config.js
Priority:
MSR_CONFIG_FILE(if set)msr.config.js(if exists)msr.config.json(if exists)
Platform-Specific Examples
Docker
Dockerfile:
FROM node:18-alpine
WORKDIR /app
# Set environment variables
ENV MSR_FOLDER=/app/migrations
ENV MSR_TABLE_NAME=migration_history
ENV MSR_LOGGING_ENABLED=true
ENV MSR_LOGGING_PATH=/app/logs
ENV MSR_BACKUP_FOLDER=/app/backups
COPY package*.json ./
RUN npm ci --production
COPY . .
CMD ["npm", "start"]
docker-compose.yml:
version: '3.8'
services:
app:
build: .
environment:
- MSR_FOLDER=/app/migrations
- MSR_TABLE_NAME=migration_history
- MSR_LOGGING_ENABLED=true
- MSR_LOGGING_PATH=/app/logs
- MSR_BACKUP_FOLDER=/app/backups
- MSR_BACKUP_TIMESTAMP=true
volumes:
- ./migrations:/app/migrations
- ./logs:/app/logs
- ./backups:/app/backups
Kubernetes
ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: msr-config
data:
MSR_FOLDER: "/app/migrations"
MSR_TABLE_NAME: "migration_history"
MSR_LOGGING_ENABLED: "true"
MSR_LOGGING_PATH: "/var/log/migrations"
MSR_BACKUP_FOLDER: "/mnt/backups"
MSR_BACKUP_TIMESTAMP: "true"
MSR_VALIDATE_BEFORE_RUN: "true"
Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
envFrom:
- configMapRef:
name: msr-config
volumeMounts:
- name: migrations
mountPath: /app/migrations
- name: logs
mountPath: /var/log/migrations
- name: backups
mountPath: /mnt/backups
volumes:
- name: migrations
persistentVolumeClaim:
claimName: migrations-pvc
- name: logs
persistentVolumeClaim:
claimName: logs-pvc
- name: backups
persistentVolumeClaim:
claimName: backups-pvc
GitHub Actions
.github/workflows/migrate.yml:
name: Run Migrations
on:
push:
branches: [main]
jobs:
migrate:
runs-on: ubuntu-latest
env:
MSR_FOLDER: ./migrations
MSR_TABLE_NAME: migration_history
MSR_STRICT_VALIDATION: true
MSR_VALIDATE_BEFORE_RUN: true
MSR_LOGGING_ENABLED: true
MSR_DRY_RUN: false
steps:
- uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run migrations
run: npm run migrate
env:
DATABASE_URL: $
Cloud Platforms
AWS ECS Task Definition
{
"containerDefinitions": [
{
"name": "app",
"image": "myapp:latest",
"environment": [
{
"name": "MSR_FOLDER",
"value": "/app/migrations"
},
{
"name": "MSR_TABLE_NAME",
"value": "migration_history"
},
{
"name": "MSR_LOGGING_ENABLED",
"value": "true"
},
{
"name": "MSR_BACKUP_FOLDER",
"value": "/mnt/efs/backups"
}
]
}
]
}
Heroku
# Set config vars
heroku config:set MSR_FOLDER=./database/migrations
heroku config:set MSR_TABLE_NAME=migration_history
heroku config:set MSR_LOGGING_ENABLED=true
heroku config:set MSR_BACKUP_FOLDER=./backups
# Deploy
git push heroku main
Environment-Specific Strategies
Development (.env)
# .env.development
MSR_FOLDER=./migrations
MSR_DRY_RUN=false
MSR_STRICT_VALIDATION=false
MSR_LOGGING_ENABLED=true
MSR_BACKUP_DELETE_BACKUP=true
Usage with dotenv:
import 'dotenv/config';
import { MigrationScriptExecutor } from '@migration-script-runner/core';
// Environment variables loaded automatically
const executor = new MigrationScriptExecutor({ handler });
await executor.up();
Staging
# .env.staging
MSR_FOLDER=./database/migrations
MSR_TABLE_NAME=migration_history
MSR_VALIDATE_BEFORE_RUN=true
MSR_STRICT_VALIDATION=false
MSR_LOGGING_ENABLED=true
MSR_LOGGING_PATH=/var/log/migrations
MSR_BACKUP_FOLDER=/var/backups
MSR_BACKUP_TIMESTAMP=true
Production
# .env.production
MSR_FOLDER=/app/migrations
MSR_TABLE_NAME=migration_history
MSR_VALIDATE_BEFORE_RUN=true
MSR_STRICT_VALIDATION=false
MSR_LOGGING_ENABLED=true
MSR_LOGGING_PATH=/var/log/migrations
MSR_BACKUP_FOLDER=/var/backups/database
MSR_BACKUP_TIMESTAMP=true
MSR_BACKUP_DELETE_BACKUP=true
Advanced Configuration
Manual Loading with ConfigLoader
For advanced use cases, use ConfigLoader directly:
import { ConfigLoader, MigrationScriptExecutor } from '@migration-script-runner/core';
// Load with waterfall approach
const config = ConfigLoader.load();
// Load with overrides (highest priority)
const config = ConfigLoader.load({
folder: './migrations',
dryRun: true
});
// Load from specific directory
const config = ConfigLoader.load({}, '/app');
const executor = new MigrationScriptExecutor({ handler , config });
See ConfigLoader API Reference for detailed documentation.
Adapter Extensibility with Automatic Parsing
New in v0.7.0: Database adapters can extend ConfigLoader to add custom environment variables with automatic parsing.
Why Use Automatic Parsing?
When building database adapters, you typically need to support additional environment variables (like POSTGRES_HOST, MYSQL_PORT, etc.). The automatic parsing feature eliminates manual mapping.
Before (Manual Mapping)
class PostgresConfigLoader extends ConfigLoader<PostgresConfig> {
applyEnvironmentVariables(config: PostgresConfig): void {
super.applyEnvironmentVariables(config); // MSR_* vars
// ❌ Manual mapping - error-prone, requires updates
if (process.env.POSTGRES_HOST) {
config.host = process.env.POSTGRES_HOST;
}
if (process.env.POSTGRES_PORT) {
config.port = parseInt(process.env.POSTGRES_PORT);
}
if (process.env.POSTGRES_SSL) {
config.ssl = process.env.POSTGRES_SSL === 'true';
}
if (process.env.POSTGRES_POOL_SIZE) {
config.poolSize = parseInt(process.env.POSTGRES_POOL_SIZE);
}
// ... 20 more properties to map manually
}
}
After (Automatic Parsing)
class PostgresConfigLoader extends ConfigLoader<PostgresConfig> {
applyEnvironmentVariables(config: PostgresConfig): void {
super.applyEnvironmentVariables(config); // MSR_* vars
// ✅ Automatic parsing - zero manual mapping!
this.autoApplyEnvironmentVariables(config, 'POSTGRES');
}
}
// Config class with typed properties
class PostgresConfig extends Config {
host: string = 'localhost';
port: number = 5432;
ssl: boolean = false;
poolSize: number = 10;
}
How It Works
- Reflection-based Discovery: Automatically finds all config properties
- Naming Convention: Converts
camelCase→SNAKE_CASEhost→POSTGRES_HOSTpoolSize→POSTGRES_POOL_SIZE
- Type Coercion: Uses default value types for automatic conversion
host: string→process.env.POSTGRES_HOSTas stringport: number→parseInt(process.env.POSTGRES_PORT)ssl: boolean→parseBoolean(process.env.POSTGRES_SSL)
Supported Types
- Primitives:
string,number,boolean - Arrays: JSON parsing (e.g.,
["pattern1", "pattern2"]) - Nested Objects: Dot-notation (e.g.,
POSTGRES_POOL_CONFIG_MIN) - Complex Objects: Recursive parsing
Example with Nested Objects
class PostgresConfig extends Config {
poolConfig: {
min: number;
max: number;
idleTimeout: number;
} = {
min: 2,
max: 10,
idleTimeout: 30000
};
}
// Environment variables (automatically mapped):
// POSTGRES_POOL_CONFIG_MIN=5
// POSTGRES_POOL_CONFIG_MAX=20
// POSTGRES_POOL_CONFIG_IDLE_TIMEOUT=60000
Custom Overrides for Special Cases
For properties requiring validation or special handling:
class PostgresConfigLoader extends ConfigLoader<PostgresConfig> {
applyEnvironmentVariables(config: PostgresConfig): void {
super.applyEnvironmentVariables(config);
const overrides = new Map();
// Custom validation for port
overrides.set('port', (cfg: PostgresConfig, envVar: string) => {
const value = process.env[envVar];
if (value) {
const port = parseInt(value, 10);
if (port >= 1 && port <= 65535) {
cfg.port = port;
} else {
console.warn(`Invalid port ${port}, using default ${cfg.port}`);
}
}
});
this.autoApplyEnvironmentVariables(config, 'POSTGRES', overrides);
}
}
Benefits
✅ Zero Manual Mapping: New properties automatically get env var support ✅ Type Safe: Uses TypeScript types for automatic coercion ✅ Consistent Naming: Automatic camelCase → SNAKE_CASE ✅ Maintainable: No updates needed when adding properties ✅ Extensible: Override system for special cases
Complete Adapter Example
import { ConfigLoader, Config } from '@migration-script-runner/core';
// 1. Define adapter config
class PostgresConfig extends Config {
host: string = 'localhost';
port: number = 5432;
database: string = 'mydb';
user: string = 'postgres';
password: string = '';
ssl: boolean = false;
poolSize: number = 10;
connectionTimeout: number = 5000;
}
// 2. Create adapter config loader
class PostgresConfigLoader extends ConfigLoader<PostgresConfig> {
applyEnvironmentVariables(config: PostgresConfig): void {
// Apply MSR_* vars
super.applyEnvironmentVariables(config);
// Automatically apply POSTGRES_* vars
this.autoApplyEnvironmentVariables(config, 'POSTGRES');
}
}
// 3. Use in your adapter
const configLoader = new PostgresConfigLoader();
const config = configLoader.load();
// Environment variables supported automatically:
// POSTGRES_HOST=db.example.com
// POSTGRES_PORT=5432
// POSTGRES_DATABASE=production_db
// POSTGRES_USER=app_user
// POSTGRES_PASSWORD=secret
// POSTGRES_SSL=true
// POSTGRES_POOL_SIZE=20
// POSTGRES_CONNECTION_TIMEOUT=10000
See ConfigLoader API Reference for complete documentation.
Using auto-envparse Directly
New in v0.7.0: MSR uses the auto-envparse library for automatic environment variable parsing. This library was extracted from MSR and is available as a standalone npm package.
Why Use auto-envparse?
- Framework-agnostic: Use outside of MSR context
- Reusable: Parse env vars for any configuration object
- No inheritance required: Works with plain objects
- Zero dependencies: Lightweight and fast
- 12-Factor App compliant: Best practices for configuration
Package: npm install auto-envparse Repository: https://github.com/vlavrynovych/auto-envparse
Basic Usage
import AutoEnvParse from 'auto-envparse';
// Your configuration object (can be any object)
const dbConfig = {
host: 'localhost',
port: 5432,
database: 'mydb',
ssl: false,
poolSize: 10
};
// Environment variables:
// DB_HOST=prod.example.com
// DB_PORT=5433
// DB_SSL=true
// DB_POOL_SIZE=20
// Parse environment variables automatically
AutoEnvParse.parse(dbConfig, { prefix: 'DB' });
// Result:
console.log(dbConfig.host); // 'prod.example.com'
console.log(dbConfig.port); // 5433 (number)
console.log(dbConfig.ssl); // true (boolean)
console.log(dbConfig.poolSize); // 20 (number)
Features
- Automatic type detection: Infers types from default values
- Naming convention: Converts
camelCase→SNAKE_CASE - Nested objects: Supports dot-notation (
DB_POOL_MIN,DB_POOL_MAX) - Nested arrays (v2.1+): Supports array indexing (
APP_SERVERS_0_HOST,APP_SERVERS_1_HOST) - Type coercion: Automatically converts strings to correct types
- Custom overrides: Add validation or special handling
- Transform functions (v2.1+): Custom transformations before assignment
- .env file loading (v2.1+): Multi-source .env file support
Example with Nested Objects
const appConfig = {
port: 3000,
cors: {
enabled: true,
origin: '*'
},
rateLimit: {
windowMs: 900000,
max: 100
}
};
// Environment:
// APP_PORT=8080
// APP_CORS_ENABLED=false
// APP_CORS_ORIGIN=https://example.com
// APP_RATE_LIMIT_MAX=1000
AutoEnvParse.parse(appConfig, { prefix: 'APP' });
Example with Custom Validation
import AutoEnvParse from 'auto-envparse';
const config = {
port: 3000,
environment: 'development'
};
// Add custom validation for port and environment
const overrides = new Map();
overrides.set('port', (obj, envVar) => {
const value = process.env[envVar];
if (value) {
const port = parseInt(value, 10);
if (port >= 1 && port <= 65535) {
obj.port = port;
} else {
console.warn(`Invalid port: ${port}, using default`);
}
}
});
// Use AutoEnvParse enum validator
overrides.set('environment', AutoEnvParse.enumValidator('environment',
['development', 'staging', 'production'],
{ caseSensitive: false }
));
// APP_PORT=8080 APP_ENVIRONMENT=production
AutoEnvParse.parse(config, { prefix: 'APP', overrides });
console.log(config.port); // 8080
console.log(config.environment); // 'production'
Advanced Features (v2.1+)
Transform Functions:
import AutoEnvParse from 'auto-envparse';
const config = {
timeout: AutoEnvParse.transform(30, (val) => val * 1000), // Convert seconds to ms
maxRetries: 3
};
// Environment: APP_TIMEOUT=60 APP_MAX_RETRIES=5
AutoEnvParse.parse(config, { prefix: 'APP' });
console.log(config.timeout); // 60000 (60 seconds * 1000)
console.log(config.maxRetries); // 5
.env File Loading:
import AutoEnvParse from 'auto-envparse';
const config = {
host: 'localhost',
port: 5432
};
// Auto-loads from .env, .env.local, etc.
AutoEnvParse.parse(config, {
prefix: 'DB',
sources: ['.env.local', '.env', 'env'] // Priority order
});
Use Cases
- Microservices: Parse service-specific configuration
- CLI tools: Load tool configuration from environment
- Testing: Mock configuration with environment variables
- Libraries: Provide env var configuration without dependencies
- Any Node.js project: Zero-config environment variable parsing
MSR Integration
MSR’s ConfigLoader internally uses auto-envparse for environment variable parsing. When you extend ConfigLoader for adapters, you’re using the same battle-tested parsing logic that’s available as a standalone package.
Validation
Ensure required environment variables are set:
import { ConfigLoader } from '@migration-script-runner/core';
// Validate required variables
ConfigLoader.validateRequired([
'DATABASE_URL',
'MSR_FOLDER',
'MSR_TABLE_NAME'
]);
// Throws error with list of missing variables if any are not set
Troubleshooting
Environment Variables Not Applied
Problem: Environment variables don’t seem to affect configuration.
Solutions:
- Check variable names - Must start with
MSR_ - Check spelling - camelCase → SNAKE_CASE (e.g.,
maxFiles→MAX_FILES) - Restart application - Environment variables are loaded at startup
- Check priority - Constructor overrides take precedence over env vars
Debug:
console.log('MSR_FOLDER:', process.env.MSR_FOLDER);
const config = ConfigLoader.load();
console.log('Loaded folder:', config.folder);
Config File Not Found
Problem: Warning: “MSR_CONFIG_FILE points to non-existent file”
Solutions:
- Check file path is relative to
process.cwd()or absolute - Verify file exists:
ls msr.config.js - Check MSR_CONFIG_FILE value:
echo $MSR_CONFIG_FILE
Invalid JSON Format
Problem: Warning: “Invalid MSR_LOGGING JSON” or “Invalid MSR_FILE_PATTERNS format”
Solutions:
- Validate JSON syntax: Use a JSON validator
- Escape properly in shell: Use single quotes
'{"key":"value"}' - Use dot-notation instead (recommended)
Instead of:
export MSR_LOGGING='{"enabled":true}' # Can be error-prone
Use:
export MSR_LOGGING_ENABLED=true # Cleaner, less error-prone
Complete Example
Production-ready configuration combining all approaches:
msr.config.js:
module.exports = {
folder: process.env.MSR_FOLDER || './migrations',
tableName: process.env.MSR_TABLE_NAME || 'schema_version',
validateBeforeRun: true,
strictValidation: process.env.NODE_ENV === 'production',
logging: {
enabled: true,
path: process.env.MSR_LOGGING_PATH || './logs'
},
backup: {
folder: process.env.MSR_BACKUP_FOLDER || './backups',
timestamp: true,
deleteBackup: process.env.NODE_ENV === 'production'
}
};
Environment variables (.env.production):
NODE_ENV=production
MSR_FOLDER=/app/migrations
MSR_TABLE_NAME=migration_history
MSR_LOGGING_PATH=/var/log/migrations
MSR_BACKUP_FOLDER=/var/backups/database
Application code:
import { MigrationScriptExecutor } from '@migration-script-runner/core';
import { DatabaseHandler } from './database';
const handler = new DatabaseHandler();
// Automatically loads: defaults → file → env vars
const executor = new MigrationScriptExecutor({ handler });
await executor.migrate();
Reference
- Environment Variables API Reference - Complete reference organized by category (Core, Validation, Logging, Backup, Transaction)
- ConfigLoader API - API documentation
- Configuration Overview - Config class documentation
- Getting Started - Quick start guide
Next Steps
- Environment Variables API Reference - Complete reference for all variables organized by category
- ConfigLoader API - Advanced usage
- Docker Deployment - Container setup
- CI/CD Integration - Pipeline configuration