Backup Settings

Configure backup file creation and storage

Table of contents

  1. Overview
  2. When Backups Are Needed
  3. BackupConfig Class
    1. Creating BackupConfig
    2. Basic Configuration
  4. Backup Options
    1. folder
      1. Behavior
      2. Examples
    2. deleteBackup
      1. Behavior
      2. Use Cases
      3. Cleanup Strategy Example
    3. timestamp
      1. Behavior
      2. Use Cases
    4. timestampFormat
      1. Common Formats
      2. Examples
    5. prefix
      1. Use Cases
    6. filename
      1. Use Cases
    7. suffix
      1. Use Cases
    8. ext
      1. Examples
  5. Filename Generation
    1. Filename Pattern
    2. Examples
    3. backupMode
      1. Backup Modes
        1. BackupMode.FULL (default)
        2. BackupMode.CREATE_ONLY
        3. BackupMode.RESTORE_ONLY
        4. BackupMode.MANUAL
      2. BackupMode with RollbackStrategy
    4. existingBackupPath
      1. Behavior
      2. Use Cases
  6. Manual Backup Methods
    1. createBackup()
    2. restoreFromBackup(backupPath?)
    3. deleteBackup()
    4. Complete Manual Workflow Example
    5. Conditional Restore Example
    6. Multiple Backup Workflow
  7. Complete Examples
    1. Development Configuration
    2. Production Configuration
    3. Audit-Compliant Configuration
    4. Multi-Environment Configuration
  8. Best Practices
    1. 1. Use Absolute Paths in Production
    2. 2. Enable Timestamps for Multiple Backups
    3. 3. Use Descriptive Prefixes and Filenames
    4. 4. Match Extension to Backup Format
    5. 5. Implement Cleanup Strategy
  9. Storage Considerations
    1. Disk Space
    2. Backup Location
  10. Troubleshooting
    1. Problem: Permission Denied
    2. Problem: Disk Full
    3. Problem: Backup Too Slow

Overview

Backup settings control how MSR creates, names, and stores database backup files. These settings are only required when using BACKUP or BOTH rollback strategies.

The BackupConfig class provides fine-grained control over backup file naming and storage location.

Backup settings are optional if you’re using RollbackStrategy.DOWN or RollbackStrategy.NONE.


When Backups Are Needed

Backup configuration is required for:

  • RollbackStrategy.BACKUP - Always uses backups
  • RollbackStrategy.BOTH - Uses backups as fallback

Backup configuration is not needed for:

  • RollbackStrategy.DOWN - Uses down() methods only
  • RollbackStrategy.NONE - No rollback

BackupConfig Class

Creating BackupConfig

import { BackupConfig } from '@migration-script-runner/core';

// Create with defaults
const backupConfig = new BackupConfig();

// Add to main config
config.backup = backupConfig;

Basic Configuration

import { Config, BackupConfig } from '@migration-script-runner/core';

const config = new Config();
config.backup = new BackupConfig();
config.backup.folder = './backups';
config.backup.deleteBackup = true;
config.backup.timestamp = true;

Backup Options

folder

Type: string Default: ./backups

Directory where backup files are stored.

// Relative path (relative to current working directory)
backupConfig.folder = './backups';

// Absolute path
backupConfig.folder = '/var/backups/msr';

// Nested location
backupConfig.folder = './database/backups';

// Environment-specific
backupConfig.folder = process.env.BACKUP_FOLDER || './backups';

Behavior

  • Directory is created automatically if it doesn’t exist
  • Backups are written to this location before migrations
  • Restored from this location on rollback

Examples

// Development - local folder
backupConfig.folder = './backups';

// Production - dedicated backup location
backupConfig.folder = '/var/lib/app/backups';

// Docker - mounted volume
backupConfig.folder = '/backups';

Ensure the folder is writable by the application user.


deleteBackup

Type: boolean Default: true

Whether to automatically delete backup files after successful migrations.

// Delete backups after success (recommended)
backupConfig.deleteBackup = true;

// Keep backups for manual review
backupConfig.deleteBackup = false;

Behavior

When true (default):

  • Backup deleted after all migrations succeed
  • Keeps disk space manageable
  • Recommended for most use cases

When false:

  • Backup preserved after success
  • Accumulates backup files over time
  • Useful for audit trails or manual verification

In production, consider setting deleteBackup = false for critical deployments to maintain recovery options.

Use Cases

// Production - delete to save space
backupConfig.deleteBackup = true;

// Audit compliance - keep backups
backupConfig.deleteBackup = false;

// Development - delete for cleanliness
backupConfig.deleteBackup = true;

// Critical systems - keep for safety
backupConfig.deleteBackup = false;

Setting deleteBackup = false will accumulate backup files over time. Implement your own cleanup strategy if disabled.

Cleanup Strategy Example

if (!backupConfig.deleteBackup) {
    // Manual cleanup - delete backups older than 30 days
    const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000);

    const oldBackups = fs.readdirSync(backupConfig.folder)
        .filter(file => {
            const stats = fs.statSync(path.join(backupConfig.folder, file));
            return stats.mtime.getTime() < thirtyDaysAgo;
        });

    oldBackups.forEach(file => {
        fs.unlinkSync(path.join(backupConfig.folder, file));
    });
}

timestamp

Type: boolean Default: true

Include timestamp in backup filename.

// With timestamp (recommended)
backupConfig.timestamp = true;
// Result: backup-2025-01-22-01-30-45.bkp

// Without timestamp
backupConfig.timestamp = false;
// Result: backup.bkp (will overwrite previous)

Behavior

When true (default):

  • Each backup gets unique timestamp
  • Multiple backups can coexist
  • Easy to identify when backup was created

When false:

  • Same filename used each time
  • New backup overwrites previous
  • Only one backup exists at a time

Use Cases

// Multiple backups - use timestamp
backupConfig.timestamp = true;
backupConfig.deleteBackup = false;

// Single backup - no timestamp needed
backupConfig.timestamp = false;
backupConfig.deleteBackup = true;

Without timestamps, each migration run overwrites the previous backup file.


timestampFormat

Type: string Default: 'YYYY-MM-DD-HH-mm-ss'

Moment.js format string for backup timestamp.

// Default format: 2025-01-22-01-30-45
backupConfig.timestampFormat = 'YYYY-MM-DD-HH-mm-ss';

// ISO format: 2025-01-22T01:30:45
backupConfig.timestampFormat = 'YYYY-MM-DDTHH:mm:ss';

// Compact format: 20250122_013045
backupConfig.timestampFormat = 'YYYYMMDD_HHmmss';

// Date only: 2025-01-22
backupConfig.timestampFormat = 'YYYY-MM-DD';

// Unix timestamp: 1737510645
backupConfig.timestampFormat = 'X';

Common Formats

Format Example Output Use Case
YYYY-MM-DD-HH-mm-ss 2025-01-22-01-30-45 Default, readable
YYYYMMDD-HHmmss 20250122-013045 Compact, sortable
YYYY-MM-DDTHH:mm:ss 2025-01-22T01:30:45 ISO 8601
X 1737510645 Unix timestamp
YYYY-MM-DD 2025-01-22 Date only

See Moment.js format documentation for all options.

Examples

// Sortable filename
backupConfig.timestampFormat = 'YYYYMMDD-HHmmss';
// backup-20250122-013045.bkp

// Human-readable
backupConfig.timestampFormat = 'YYYY-MM-DD-HH-mm-ss';
// backup-2025-01-22-01-30-45.bkp

// ISO standard
backupConfig.timestampFormat = 'YYYY-MM-DDTHH:mm:ss';
// backup-2025-01-22T01:30:45.bkp

prefix

Type: string Default: 'backup'

Filename prefix for backup files.

// Default prefix
backupConfig.prefix = 'backup';
// Result: backup-2025-01-22-01-30-45.bkp

// Custom prefix
backupConfig.prefix = 'msr-backup';
// Result: msr-backup-2025-01-22-01-30-45.bkp

// Application-specific
backupConfig.prefix = 'myapp-db';
// Result: myapp-db-2025-01-22-01-30-45.bkp

Use Cases

// Default
backupConfig.prefix = 'backup';

// Application identification
backupConfig.prefix = 'myapp-backup';

// Database identification
backupConfig.prefix = 'postgres-backup';

// Environment prefix
backupConfig.prefix = `backup-${process.env.NODE_ENV}`;
// backup-production, backup-staging, etc.

filename

Type: string Default: '' (empty)

Custom filename component inserted between prefix and timestamp.

// No custom filename (default)
backupConfig.filename = '';
// Result: backup-2025-01-22-01-30-45.bkp

// Add environment
backupConfig.filename = 'production';
// Result: backup-production-2025-01-22-01-30-45.bkp

// Add database name
backupConfig.filename = 'users-db';
// Result: backup-users-db-2025-01-22-01-30-45.bkp

Use Cases

// Environment identification
backupConfig.filename = process.env.NODE_ENV;
// backup-production-2025-01-22-01-30-45.bkp

// Database identification
backupConfig.filename = 'primary-db';
// backup-primary-db-2025-01-22-01-30-45.bkp

// Version identification
backupConfig.filename = 'v2';
// backup-v2-2025-01-22-01-30-45.bkp

// Multi-tenant
backupConfig.filename = `tenant-${tenantId}`;
// backup-tenant-123-2025-01-22-01-30-45.bkp

suffix

Type: string Default: '' (empty)

Filename suffix inserted before extension.

// No suffix (default)
backupConfig.suffix = '';
// Result: backup-2025-01-22-01-30-45.bkp

// Add version suffix
backupConfig.suffix = 'v2';
// Result: backup-2025-01-22-01-30-45-v2.bkp

// Add node identifier
backupConfig.suffix = 'node1';
// Result: backup-2025-01-22-01-30-45-node1.bkp

Use Cases

// Version suffix
backupConfig.suffix = 'v1';

// Server identification
backupConfig.suffix = `server-${process.env.HOSTNAME}`;

// Backup type
backupConfig.suffix = 'full';
backupConfig.suffix = 'incremental';

ext

Type: string Default: '.bkp'

File extension for backup files.

// Default extension
backupConfig.ext = '.bkp';

// Custom extensions
backupConfig.ext = '.backup';
backupConfig.ext = '.json';  // For JSON serialization
backupConfig.ext = '.sql';   // For SQL dumps
backupConfig.ext = '.dump';  // For binary dumps

// Without leading dot (automatically added)
backupConfig.ext = 'bkp';  // Same as '.bkp'

Examples

// Generic backup
backupConfig.ext = '.bkp';

// SQL dump
backupConfig.ext = '.sql';

// JSON format
backupConfig.ext = '.json';

// PostgreSQL dump
backupConfig.ext = '.pgdump';

// Compressed backup
backupConfig.ext = '.bkp.gz';

The extension can be specified with or without the leading dot (.bkp or bkp).


Filename Generation

Filename Pattern

The final backup filename is constructed from all options:

{prefix}[-{filename}][-{timestamp}][-{suffix}]{ext}

Components in brackets [] are optional based on configuration.

Examples

Default configuration:

backupConfig.prefix = 'backup';
backupConfig.filename = '';
backupConfig.timestamp = true;
backupConfig.timestampFormat = 'YYYY-MM-DD-HH-mm-ss';
backupConfig.suffix = '';
backupConfig.ext = '.bkp';

// Result: backup-2025-01-22-01-30-45.bkp

Production configuration:

backupConfig.prefix = 'db-backup';
backupConfig.filename = 'production';
backupConfig.timestamp = true;
backupConfig.timestampFormat = 'YYYYMMDD-HHmmss';
backupConfig.suffix = '';
backupConfig.ext = '.sql';

// Result: db-backup-production-20250122-013045.sql

Multi-tenant configuration:

backupConfig.prefix = 'backup';
backupConfig.filename = `tenant-${tenantId}`;
backupConfig.timestamp = true;
backupConfig.timestampFormat = 'YYYY-MM-DD-HH-mm-ss';
backupConfig.suffix = 'v2';
backupConfig.ext = '.json';

// Result: backup-tenant-123-2025-01-22-01-30-45-v2.json

Simple configuration (no timestamp):

backupConfig.prefix = 'latest';
backupConfig.filename = '';
backupConfig.timestamp = false;
backupConfig.suffix = '';
backupConfig.ext = '.backup';

// Result: latest.backup (overwrites each time)

backupMode

Type: BackupMode Default: BackupMode.FULL

Controls when backups are created and whether automatic restore occurs on failure.

import { BackupMode, RollbackStrategy } from '@migration-script-runner/core';

// Full automatic backup and restore (default)
config.backupMode = BackupMode.FULL;
config.rollbackStrategy = RollbackStrategy.BACKUP;

Backup Modes

BackupMode.FULL (default)

Complete automatic backup and restore workflow:

  • Creates backup before migrations
  • Restores automatically on failure
  • Deletes backup on success
config.backupMode = BackupMode.FULL;
config.rollbackStrategy = RollbackStrategy.BACKUP;

await executor.migrate();
// Backup created → migrations run → backup deleted on success
// OR: Backup created → migrations fail → restore from backup
BackupMode.CREATE_ONLY

Creates backup but doesn’t restore automatically:

  • Creates backup before migrations
  • Does NOT restore on failure
  • Keeps backup file for manual inspection
config.backupMode = BackupMode.CREATE_ONLY;
config.rollbackStrategy = RollbackStrategy.DOWN;
config.backup.deleteBackup = false;

await executor.migrate();
// Backup created → migrations run → down() methods used on failure
// Backup file kept for safety/manual restore

Use cases:

  • Using down() methods for rollback but want backup safety net
  • Manual inspection/decision before restore
  • External monitoring handles restore decisions
BackupMode.RESTORE_ONLY

Restores from existing backup without creating new one:

  • Does NOT create backup
  • Restores from config.backup.existingBackupPath on failure
  • Requires existingBackupPath to be set
config.backupMode = BackupMode.RESTORE_ONLY;
config.rollbackStrategy = RollbackStrategy.BACKUP;
config.backup.existingBackupPath = './backups/pre-deploy.bkp';

await executor.migrate();
// No backup creation → migrations run → restore from existing on failure

Use cases:

  • External backup system already created backup
  • CI/CD pipeline with backup in earlier step
  • Re-attempting failed migration with known-good backup

Important: Must set config.backup.existingBackupPath:

// ✅ Correct usage
config.backupMode = BackupMode.RESTORE_ONLY;
config.backup.existingBackupPath = './backups/my-backup.bkp';

// ❌ Will throw error - missing existingBackupPath
config.backupMode = BackupMode.RESTORE_ONLY;
// Error: BackupMode.RESTORE_ONLY requires existingBackupPath configuration
BackupMode.MANUAL

No automatic backup or restore - full manual control:

  • Does NOT create backup automatically
  • Does NOT restore automatically on failure
  • Use public methods for manual workflow
config.backupMode = BackupMode.MANUAL;
config.rollbackStrategy = RollbackStrategy.BACKUP;

// Manual workflow
const backupPath = await executor.createBackup();
try {
  await executor.migrate();
  executor.deleteBackup();
} catch (error) {
  await executor.restoreFromBackup(backupPath);
}

Use cases:

  • Full control over backup/restore timing
  • Custom backup logic or conditions
  • Integrating with external backup systems
  • Complex multi-step workflows

BackupMode with RollbackStrategy

BackupMode works in conjunction with rollbackStrategy:

RollbackStrategy BackupMode Effect
BACKUP BackupMode controls backup/restore behavior
BOTH BackupMode controls backup/restore, down() runs first
DOWN BackupMode ignored, only down() methods used
NONE BackupMode ignored, no rollback
// BACKUP strategy - backup/restore controlled by backupMode
config.rollbackStrategy = RollbackStrategy.BACKUP;
config.backupMode = BackupMode.FULL; // Creates + restores
config.backupMode = BackupMode.CREATE_ONLY; // Creates only
config.backupMode = BackupMode.RESTORE_ONLY; // Restores only
config.backupMode = BackupMode.MANUAL; // Manual control

// BOTH strategy - down() first, then backup/restore per backupMode
config.rollbackStrategy = RollbackStrategy.BOTH;
config.backupMode = BackupMode.FULL; // down() → backup if down() fails
config.backupMode = BackupMode.CREATE_ONLY; // down() → no backup restore

// DOWN strategy - backupMode has no effect
config.rollbackStrategy = RollbackStrategy.DOWN;
config.backupMode = BackupMode.FULL; // Ignored, only down() used

existingBackupPath

Type: string | undefined Default: undefined

Path to existing backup file for BackupMode.RESTORE_ONLY.

// Use existing backup for restore
config.backupMode = BackupMode.RESTORE_ONLY;
config.backup.existingBackupPath = './backups/pre-deploy-2025-01-22.bkp';

// Absolute path
config.backup.existingBackupPath = '/var/backups/myapp/manual-backup.bkp';

Behavior

When BackupMode.RESTORE_ONLY:

  • Required - migrations will fail if not set
  • Used as restore source if migrations fail
  • No new backup created

Other backup modes:

  • Optional - ignored if set
  • No effect on backup/restore behavior

Use Cases

// External backup system
config.backupMode = BackupMode.RESTORE_ONLY;
config.backup.existingBackupPath = '/mnt/backup-system/latest.bkp';

// CI/CD pipeline with separate backup step
config.backupMode = BackupMode.RESTORE_ONLY;
config.backup.existingBackupPath = process.env.BACKUP_PATH;

// Manual backup before risky migration
const manualBackup = './backups/before-major-update.bkp';
config.backupMode = BackupMode.RESTORE_ONLY;
config.backup.existingBackupPath = manualBackup;

Manual Backup Methods

When using BackupMode.MANUAL or for custom workflows, MSR provides public methods for manual backup/restore control.

createBackup()

Create a database backup manually.

const backupPath = await executor.createBackup();
console.log(`Backup created: ${backupPath}`);
// Backup created: ./backups/backup-2025-01-22-01-30-45.bkp

Returns: Promise<string> - Absolute path to created backup file

Use cases:

  • Manual backup before risky operations
  • Custom backup timing/conditions
  • Integration with external systems

restoreFromBackup(backupPath?)

Restore database from backup file.

// Restore from specific backup
await executor.restoreFromBackup('./backups/my-backup.bkp');

// Restore from most recent backup (created by createBackup())
await executor.restoreFromBackup();

Parameters:

  • backupPath (optional): Path to backup file. If not provided, uses most recent backup.

Returns: Promise<void>

Use cases:

  • Manual restore after failed migration
  • Testing restore process
  • Selective restore based on conditions

deleteBackup()

Delete backup file from disk.

executor.deleteBackup();

Behavior:

  • Only deletes if config.backup.deleteBackup = true
  • Safe to call multiple times
  • No error if file already deleted

Use cases:

  • Manual cleanup after successful migrations
  • Custom cleanup logic
  • Conditional backup deletion

Complete Manual Workflow Example

import { MigrationScriptExecutor, Config, BackupMode } from '@migration-script-runner/core';

const config = new Config();
config.backupMode = BackupMode.MANUAL;
config.backup.deleteBackup = true;

const executor = new MigrationScriptExecutor({ handler }, config);

// Step 1: Create backup manually
console.log('Creating backup...');
const backupPath = await executor.createBackup();
console.log(`Backup created: ${backupPath}`);

try {
  // Step 2: Run migrations
  console.log('Running migrations...');
  await executor.migrate();

  // Step 3: Success - clean up
  console.log('Migrations successful!');
  executor.deleteBackup();

} catch (error) {
  // Step 4: Failure - restore
  console.error('Migration failed:', error.message);
  console.log('Restoring from backup...');

  await executor.restoreFromBackup(backupPath);
  console.log('Database restored to previous state');

  // Optional: Keep backup for investigation
  // executor.deleteBackup(); // Uncomment to delete
}

Conditional Restore Example

const backupPath = await executor.createBackup();

try {
  await executor.migrate();
  executor.deleteBackup();
} catch (error) {
  // Only restore for certain error types
  if (shouldRestore(error)) {
    await executor.restoreFromBackup(backupPath);
  } else {
    console.log('Keeping database as-is for debugging');
  }
}

function shouldRestore(error: Error): boolean {
  // Custom logic to determine if restore is needed
  return error.message.includes('constraint violation');
}

Multiple Backup Workflow

// Create multiple backups for different scenarios
config.backup.deleteBackup = false;

// Before migrations
const beforeBackup = await executor.createBackup();

// After first batch
await runFirstBatch();
const midpointBackup = await executor.createBackup();

// After all migrations
await runSecondBatch();
const finalBackup = await executor.createBackup();

// Selective restore based on which batch failed
if (secondBatchFailed) {
  await executor.restoreFromBackup(midpointBackup);
}

Complete Examples

Development Configuration

Simple backup for local development:

const config = new Config();
config.rollbackStrategy = RollbackStrategy.BACKUP;

config.backup = new BackupConfig();
config.backup.folder = './backups';
config.backup.deleteBackup = true;
config.backup.timestamp = true;
config.backup.ext = '.bkp';

// Result: ./backups/backup-2025-01-22-01-30-45.bkp

Production Configuration

Organized backups with environment identification:

const config = new Config();
config.rollbackStrategy = RollbackStrategy.BOTH;

config.backup = new BackupConfig();
config.backup.folder = '/var/lib/myapp/backups';
config.backup.deleteBackup = true;
config.backup.prefix = 'myapp-db';
config.backup.filename = process.env.NODE_ENV;
config.backup.timestamp = true;
config.backup.timestampFormat = 'YYYYMMDD-HHmmss';
config.backup.ext = '.sql';

// Result: /var/lib/myapp/backups/myapp-db-production-20250122-013045.sql

Audit-Compliant Configuration

Keep all backups for compliance:

const config = new Config();
config.rollbackStrategy = RollbackStrategy.BACKUP;

config.backup = new BackupConfig();
config.backup.folder = '/mnt/audit-backups';
config.backup.deleteBackup = false;  // Keep all backups
config.backup.prefix = 'audit-backup';
config.backup.timestamp = true;
config.backup.timestampFormat = 'YYYY-MM-DD-HH-mm-ss';
config.backup.ext = '.sql';

// Result: /mnt/audit-backups/audit-backup-2025-01-22-01-30-45.sql
// (Backups accumulate, implement cleanup strategy)

Multi-Environment Configuration

Different settings per environment:

const config = new Config();
config.rollbackStrategy = RollbackStrategy.BOTH;

config.backup = new BackupConfig();

// Environment-specific folder
config.backup.folder = process.env.NODE_ENV === 'production'
    ? '/var/backups/production'
    : './backups';

// Delete in dev, keep in production
config.backup.deleteBackup = process.env.NODE_ENV !== 'production';

// Environment in filename
config.backup.filename = process.env.NODE_ENV;

// Common settings
config.backup.timestamp = true;
config.backup.timestampFormat = 'YYYYMMDD-HHmmss';
config.backup.ext = '.bkp';

Best Practices

1. Use Absolute Paths in Production

// ✅ Good - absolute path
config.backup.folder = '/var/lib/myapp/backups';

// ❌ Risky - relative path may change based on working directory
config.backup.folder = './backups';

2. Enable Timestamps for Multiple Backups

// ✅ Good - unique backups
config.backup.timestamp = true;
config.backup.deleteBackup = false;

// ❌ Bad - single backup overwrites
config.backup.timestamp = false;
config.backup.deleteBackup = false;

3. Use Descriptive Prefixes and Filenames

// ✅ Good - clear identification
config.backup.prefix = 'myapp-postgres';
config.backup.filename = process.env.NODE_ENV;

// ❌ Bad - unclear
config.backup.prefix = 'bk';
config.backup.filename = 'temp';

4. Match Extension to Backup Format

// ✅ Good - extension matches format
config.backup.ext = '.sql';  // For SQL dump
config.backup.ext = '.json'; // For JSON serialization

// ❌ Misleading - doesn't match format
config.backup.ext = '.sql';  // But using JSON serialization

5. Implement Cleanup Strategy

// ✅ Good - cleanup old backups
config.backup.deleteBackup = false;

// Add cleanup job
setInterval(() => {
    cleanupOldBackups(config.backup.folder, 30); // Keep 30 days
}, 24 * 60 * 60 * 1000);

// ❌ Bad - no cleanup, disk fills up
config.backup.deleteBackup = false;
// No cleanup strategy!

Storage Considerations

Disk Space

Calculate required disk space:

// Estimate: backup size ≈ database size
const dbSize = await getDatabaseSize();
const backupsPerDay = 10;
const retentionDays = 30;

const requiredSpace = dbSize * backupsPerDay * retentionDays;

if (availableSpace < requiredSpace) {
    // Enable deletion or reduce retention
    config.backup.deleteBackup = true;
}

Backup Location

Choose appropriate backup location:

// Same disk (fast, less safe)
config.backup.folder = '/var/lib/myapp/backups';

// Different disk (safer)
config.backup.folder = '/mnt/backup-disk/myapp';

// Network storage (safest, slower)
config.backup.folder = '/mnt/nfs/backups/myapp';

// Docker volume (portable)
config.backup.folder = '/backups';  // Mounted volume

Troubleshooting

Problem: Permission Denied

Cause: Backup folder not writable

Solution:

# Check permissions
ls -ld /var/lib/myapp/backups

# Fix permissions
sudo chown myapp:myapp /var/lib/myapp/backups
sudo chmod 755 /var/lib/myapp/backups

Problem: Disk Full

Cause: Too many backups accumulated

Solution:

// Enable automatic deletion
config.backup.deleteBackup = true;

// Or implement cleanup
cleanupOldBackups(config.backup.folder, retentionDays);

Problem: Backup Too Slow

Cause: Large database or slow storage

Solution:

// Switch to DOWN strategy
config.rollbackStrategy = RollbackStrategy.DOWN;

// Or use faster storage
config.backup.folder = '/dev/shm/backups';  // RAM disk (temporary)