east - Database Migration Tool

2.0.3 · active · verified Wed Apr 22

east is a Node.js database migration tool designed to manage schema changes across various database systems including MongoDB, SQLite, PostgreSQL, MySQL, and Couchbase. Currently stable at version 2.0.3, it primarily focuses on providing a robust CLI for migration management but also offers programmatic access. Its core philosophy is to integrate with existing database drivers, allowing developers to use their familiar database-specific syntax within migration scripts rather than imposing a universal ORM or query builder. This tool supports Node.js versions 10.17.0 and higher, with specific adapter requirements potentially varying. It actively supports modern JavaScript features, including TypeScript for migration files and ECMAScript Modules (ESM) for configuration and migrations, making it adaptable to contemporary Node.js project setups. Releases appear to be driven by feature development and maintenance needs.

Common errors

Warnings

Install

Imports

Quickstart

This quickstart demonstrates the programmatic usage of `east` to initialize a migration directory, create a new migration file, populate it with sample migration logic, and then execute the migrations. It includes a minimal mock adapter to illustrate how `east` interacts with a database, emphasizing its adapter-based design.

import { migrate, create } from 'east';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { promises as fs } from 'node:fs';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const migrationsDir = path.join(__dirname, 'my-app-migrations');

// A minimal mock adapter for demonstration purposes.
// In a real application, you would install and use an official adapter
// like `east-adapter-mongodb` or `east-adapter-pg`.
const mockAdapter = {
  connect: async (url) => {
    console.log(`[Mock DB] Attempting connection to ${url}...`);
    return { client: {}, db: { // Simulate a minimal DB object
      collection: (name) => ({ // Mock a collection for storing migration names
        find: () => ({ toArray: async () => [] }), // No executed migrations initially
        insertOne: async (doc) => { console.log(`[Mock DB] Storing migration record: ${doc.name}`); },
        deleteOne: async (query) => { console.log(`[Mock DB] Removing migration record: ${query.name}`); }
      })
    } };
  },
  disconnect: async () => { console.log('[Mock DB] Disconnecting...'); },
  getExecutedMigrationNames: async (db) => {
    // In a real adapter, this would query a specific collection/table.
    return db.collection('east_migrations').find().toArray().then(docs => docs.map(d => d.name));
  },
  markMigrationExecuted: async (db, name) => {
    await db.collection('east_migrations').insertOne({ name, createdAt: new Date() });
    console.log(`[Mock DB] Marked migration '${name}' as executed.`);
  },
  unmarkMigrationExecuted: async (db, name) => {
    await db.collection('east_migrations').deleteOne({ name });
    console.log(`[Mock DB] Unmarked migration '${name}' (rolled back).`);
  }
};

async function runEastProgrammatically() {
  // Ensure migration directory exists (equivalent to parts of `east init` CLI)
  await fs.mkdir(migrationsDir, { recursive: true });
  console.log(`Migration directory created or already exists: ${migrationsDir}`);

  // Create a new migration file
  console.log('\n--- Creating a new migration file ---');
  const { filepath, basename } = await create({
    dir: migrationsDir,
    basename: 'initial-setup-db',
    // Optional: template: path.join(__dirname, 'custom-template.js')
  });
  console.log(`Created migration: ${filepath}`);

  // Write some simple content into the created migration file
  const migrationContent = `
export async function migrate(db) {
  console.log('Running migration: ${basename}');
  // Simulate a database operation
  await db.collection('users').insertOne({ name: 'Alice', email: 'alice@example.com' });
  console.log('Added initial user data.');
}

export async function rollback(db) {
  console.log('Rolling back migration: ${basename}');
  await db.collection('users').deleteOne({ name: 'Alice' });
  console.log('Removed initial user data.');
}
`;
  await fs.writeFile(filepath, migrationContent);
  console.log('Populated migration file with sample content.');

  // Run the migrations
  console.log('\n--- Running migrations ---');
  try {
    await migrate({
      url: 'mockdb://localhost:9999/test-db',
      dir: migrationsDir,
      adapter: mockAdapter,
      // esModules: true, // Necessary if your migration files use 'import/export' and you're not in 'type: module'
      silent: false, // Show detailed logs
      trace: true // Show error stack traces
    });
    console.log('\nMigrations completed successfully.');
  } catch (error) {
    console.error('\nMigration failed:', error);
    process.exit(1);
  }
}

runEastProgrammatically().catch(console.error);

view raw JSON →