east - Database Migration Tool
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
-
Error: Cannot find module 'east-adapter-mongodb' (or similar adapter module)
cause The required database adapter package (e.g., `east-adapter-mongodb`, `east-adapter-pg`) was not installed, or the specified adapter name in your `east` configuration does not match an installed package.fixInstall the specific adapter package for your database: `npm install east-adapter-mongodb` (replace `mongodb` with your database of choice). Verify that your `east` configuration (e.g., `east.config.js`) or CLI command correctly specifies the adapter name. -
SyntaxError: Cannot use import statement outside a module
cause You are attempting to use ES Module `import`/`export` syntax in a migration file or configuration without Node.js being configured to treat the file as an ES module. This typically happens when using `.js` files without `"type": "module"` in `package.json` or without the `--es-modules` CLI flag.fixIf using the `east` CLI, add the `--es-modules` flag. If your project is ESM-first, ensure your `package.json` has `"type": "module"` or use `.mjs` file extensions for your migration and config files. For TypeScript, ensure your `tsconfig.json` `module` option is set appropriately (e.g., `esnext`, `nodenext`). -
Error: Migration 'xxxxxxxxxxxx-my-migration-name' failed: [Database specific error]
cause An error occurred during the execution of a specific migration script. This is typically due to issues within the migration logic itself, such as incorrect SQL queries, invalid MongoDB operations, or problems with the database connection from within the migration.fixExamine the database-specific error message in the stack trace provided by `east` (enable `--trace` for verbose errors). Debug your migration file (`xxxxxxxxxxxx-my-migration-name.js` or `.ts`) to fix the logic, database interaction, or connection issues. Ensure the target database is accessible and credentials are correct. -
Error: Timeout of XXXms reached for migration 'YYYYY'
cause A migration script took longer than the configured timeout to complete, or the database connection itself timed out while `east` was waiting for an operation to finish.fixIncrease the timeout by using the `--timeout <ms>` CLI option or by setting the `timeout` property in your programmatic configuration. Investigate the migration script for long-running operations or optimize database queries to run within the default or specified timeout. Additionally, check network connectivity and database server load.
Warnings
- gotcha east itself requires Node.js >= 10.17.0. However, specific database adapters might have different or stricter Node.js version requirements, which could lead to compatibility issues if not checked. Always consult the documentation for the particular adapter you are using.
- gotcha When using `east` with ECMAScript Modules (ESM) for configuration, migration files, or custom adapters, you must either enable the `--es-modules` flag via the CLI or ensure your `package.json` specifies `"type": "module"` for proper module resolution. Otherwise, you may encounter `SyntaxError` related to `import`/`export` statements.
- gotcha east does not provide universal database APIs. Instead, it expects you to use your database's native driver or ORM within migration files. This means you need to install and configure the specific database client (e.g., `mongodb` for MongoDB, `pg` for PostgreSQL) separately and correctly handle its connection from within your migration scripts.
- gotcha The `snyk.io` badge indicates that `east` might have known vulnerabilities or dependencies with vulnerabilities. While actively maintained, it is crucial to regularly check the Snyk report for `east` to ensure supply chain security and address any critical issues promptly.
Install
-
npm install east -
yarn add east -
pnpm add east
Imports
- migrate
const east = require('east'); east.migrate(...);import { migrate } from 'east'; - create
import East from 'east'; East.create(...);
import { create } from 'east'; - EastConfig
import type { EastConfig } from 'east';
Quickstart
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);