Twin Documentation
  • Overview
  • Consumer
  • Developer
  • Operations
Dashboard Guide
Deploy
    Backend DeployFrontend DeployMigrations Checklist
MonitoringContracts & AddressesTroubleshooting
powered by Zudoku
Deploy

Migrations Checklist

Before Deploy

  • Migration file uses import type { Knex } from 'knex' (NOT import { Knex }) -- Knex is CJS and migrations run with sucrase/ESM.
  • Any data inserts use check-before-insert for idempotency:
    Code
    const exists = await knex('table').where('key', 'VALUE').first(); if (!exists) { await knex('table').insert({...}); }
  • Migration tested locally: cd twin-backend/packages/database && npm run migrate
  • Migration rolls back cleanly: cd twin-backend/packages/database && npm run migrate:rollback
  • No hardcoded IDs (resolve dynamically from DB, e.g., SELECT id FROM ops_token WHERE address = ? AND network = ?).
  • Partial unique indexes use WHERE deleted_at IS NULL for soft-delete tables.

Deploy with Migrations

Code
Deploy new backend image (includes migration files) | v ECS starts new task | v Application startup runs pending migrations | v Migrations succeed? ----No----> Task fails, ECS rolls back to previous task | Yes | v Application starts normally | v Health check passes

Commands to Run in Production

If migrations need to be run manually (e.g., outside the deploy pipeline):

TerminalCode
# Connect to the production database (via bastion or ECS exec) # Run pending migrations npx knex migrate:latest --knexfile knexfile.ts # Check migration status npx knex migrate:status --knexfile knexfile.ts # Rollback last batch (use with caution) npx knex migrate:rollback --knexfile knexfile.ts

What Can Go Wrong

Column already exists

If a migration tries to add a column that already exists (e.g., from a partial previous run):

Code
migration failed with error: column "xyz" of relation "table" already exists

Fix: Wrap in a check: if (!(await knex.schema.hasColumn('table', 'xyz'))).

Batch rollback removes too much

migrate:rollback rolls back the entire last batch, not just one migration. If the batch contained multiple migrations, all of them will be rolled back.

Fix: Be intentional about batches. If you need to rollback a single migration, you may need to do it manually.

Lock stuck

If a migration crashes mid-execution, the knex_migrations_lock table may be left in a locked state, preventing future migrations from running.

Code
Migration table is already locked

Fix:

Code
DELETE FROM knex_migrations_lock;

Or:

Code
UPDATE knex_migrations_lock SET is_locked = 0;

Post-Migration Checks

  • Verify new tables/columns exist in the database.
  • Verify seed data was inserted (if applicable).
  • Check that the application is using the new schema correctly (no runtime errors).
  • Verify indexes were created (especially partial unique indexes).
  • Run a quick smoke test of affected endpoints.
Last modified on May 12, 2026
Frontend DeployMonitoring
On this page
  • Before Deploy
  • Deploy with Migrations
  • Commands to Run in Production
  • What Can Go Wrong
    • Column already exists
    • Batch rollback removes too much
    • Lock stuck
  • Post-Migration Checks
TypeScript