Postgres Migrations
The `postgres-migrations` package provides a robust database migration solution for PostgreSQL, directly inspired by Stack Overflow's deployment methodology. Currently at version 5.3.0, it offers a stable and opinionated approach to managing database schema changes. Key differentiators include its strict sequential SQL file-based ordering, which explicitly avoids timestamp-based naming to ensure consistent execution order across all environments. The library deliberately eschews 'down' migrations, advocating for a 'roll forward' philosophy where issues are addressed by applying new incremental migrations. It enforces database integrity by performing hash checks on previously applied migration files, preventing accidental or unauthorized modifications. The package maintains a hidden `migrations` table to track applied scripts and requires Node.js 10.17.0+ and PostgreSQL 9.4+.
Common errors
-
ERROR: Migration file 'X_my-migration.sql' has been modified since it was applied. Aborting.
cause A migration SQL file that was previously successfully applied to the database has been altered on the filesystem.fixRevert the changes to the migration file `X_my-migration.sql` to its original state, or ensure no applied migration files are modified. All subsequent changes should be in new migration files. -
ERROR: Found multiple migration files with the same sequence number: X_migration1.sql, X_migration2.sql. Please resolve this conflict.
cause Two or more migration files in the specified directory share the same numerical prefix, leading to an ambiguous execution order.fixRename one of the conflicting migration files (e.g., `X_migration2.sql` to `Y_migration2.sql` where `Y` is the next available sequence number) to ensure all migration files have unique, sequential prefixes. -
TypeError: client.connect is not a function
cause An invalid `pg` client object (e.g., a raw configuration object or an uninstantiated `pg` class) was passed where a connected client or pool was expected.fixEnsure you are passing an instantiated `pg.Client`, `pg.Pool`, or `pg.PoolClient` instance that has already called `.connect()` (for `Client`) or is ready for use (for `Pool`). Alternatively, pass the database connection config directly.
Warnings
- breaking This library intentionally does not support 'down' migrations or rollbacks. The philosophy is to 'roll forward' by applying new migrations to correct any issues, which may be a significant paradigm shift for users accustomed to rollback mechanisms.
- gotcha Modifying migration files that have already been applied to a database will cause the migration process to fail due to hash mismatches. The library performs integrity checks to ensure that previously run migrations remain unchanged.
- gotcha If two migration files are created with the same sequential prefix (e.g., `5_add_column_a.sql` and `5_add_column_b.sql`), the migration process will detect this conflict and refuse to proceed. This is to prevent inconsistent migration ordering.
- gotcha The `ensureDatabaseExists` option, which defaults to `false`, might change its default behavior in future major versions. If `false`, the database must exist before migrations can run.
- gotcha The library requires Node.js version 10.17.0 or higher and PostgreSQL version 9.4 or higher. Older environments are not supported and may lead to unexpected behavior or errors.
Install
-
npm install postgres-migrations -
yarn add postgres-migrations -
pnpm add postgres-migrations
Imports
- migrate
const { migrate } = require('postgres-migrations')import { migrate } from 'postgres-migrations' - loadMigrationFiles
const { loadMigrationFiles } = require('postgres-migrations')import { loadMigrationFiles } from 'postgres-migrations' - pg.Client
const { Client } = require('pg')import { Client } from 'pg'
Quickstart
import { migrate } from 'postgres-migrations';
import { Client } from 'pg';
import path from 'path';
async function runMigrations() {
const dbConfig = {
database: process.env.DB_NAME ?? 'your_database',
user: process.env.DB_USER ?? 'postgres',
password: process.env.DB_PASSWORD ?? 'password',
host: process.env.DB_HOST ?? 'localhost',
port: parseInt(process.env.DB_PORT ?? '5432', 10),
// ensureDatabaseExists: true // Uncomment if you want the library to create the database if it doesn't exist
};
const client = new Client(dbConfig);
await client.connect();
try {
console.log('Starting database migrations...');
const migrationsPath = path.resolve(__dirname, 'migrations');
await migrate({ client }, migrationsPath);
console.log('Database migrations completed successfully.');
} catch (error) {
console.error('Migration failed:', error);
process.exit(1);
} finally {
await client.end();
}
}
// Example migrations directory structure:
// my-project/
// ├── src/
// │ └── index.ts (or .js)
// └── migrations/
// ├── 1_create_users_table.sql
// └── 2_add_posts_table.sql
runMigrations();