Storage Drivers
Abstract storage for migration files, journals, and snapshots
What Storage Drivers Do
- Store migration SQL files - Up and down migrations
- Store the journal - Index of all migrations with checksums
- Store schema snapshots - Current schema state for diffing
- Handle backups - Archive migrations before modification
Available Drivers
| Driver | Storage | Best For |
|---|---|---|
| Filesystem | Local files | Development, CI/CD, version control |
Abstract Interface
All storage drivers implement three core methods:
abstract class MigrationStorageDriver {
abstract get(path: string): Promise<string | null>;
abstract put(path: string, content: string): Promise<void>;
abstract delete(path: string): Promise<void>;
}
| Method | Description |
|---|---|
get(path) |
Read content from path, returns null if not found |
put(path, content) |
Write content to path, creates directories as needed |
delete(path) |
Delete file at path, no-op if not found |
The base class builds everything else (journal, snapshot, migration, and backup handling) on top of these three methods, so a custom driver only needs to implement them.
Directory Structure
The filesystem driver uses this structure:
migrations/
├── 0000_initial.sql # Up migrations
├── 0001_add-users.sql
├── 0002_add-posts.sql
└── meta/
├── _journal.json # Migration index
├── _snapshot.json # Current schema
├── _down/ # Down migrations
│ ├── 0000_initial.sql
│ ├── 0001_add-users.sql
│ └── 0002_add-posts.sql
├── _backup/ # Backups before modification
└── _archive/ # Archived migrations
Custom Storage Drivers
To implement a custom storage driver, extend MigrationStorageDriver:
import { MigrationStorageDriver } from "viborm/migrations";
class S3StorageDriver extends MigrationStorageDriver {
constructor(
private bucket: string,
private prefix: string = "migrations"
) {
super("s3");
}
async get(path: string): Promise<string | null> {
const key = `${this.prefix}/${path}`;
try {
const response = await s3.getObject({ Bucket: this.bucket, Key: key });
return response.Body?.toString("utf-8") ?? null;
} catch (e) {
if (e.name === "NoSuchKey") return null;
throw e;
}
}
async put(path: string, content: string): Promise<void> {
const key = `${this.prefix}/${path}`;
await s3.putObject({
Bucket: this.bucket,
Key: key,
Body: content,
ContentType: "text/plain",
});
}
async delete(path: string): Promise<void> {
const key = `${this.prefix}/${path}`;
try {
await s3.deleteObject({ Bucket: this.bucket, Key: key });
} catch (e) {
if (e.name !== "NoSuchKey") throw e;
}
}
}
Use your custom driver:
const storage = new S3StorageDriver("my-bucket", "migrations");
const migrations = createMigrationClient(client, {
storageDriver: storage,
});