← Back to Insights

Scaling decisions

Performing Database Migrations Without Downtime

By Team · Thu Jun 11 2026 · 4 min read

Performing Database Migrations Without Downtime
A successful database migration without downtime requires an incremental, backward-compatible approach. Changes are deployed in stages. Each stage ensures application compatibility with both old and new schema versions. This minimizes risk and maintains continuous service availability.

Why This Happens

Database schema changes often break application code. Direct modifications can cause immediate application errors. This is especially true when columns are dropped or types change. Latency in code deployment also creates problems. An application instance might query a schema version that no longer exists. This leads to runtime exceptions. Data volume also complicates migrations. Large tables require long alteration times. Locking these tables during changes stops application writes and reads. Transactional DDL statements are not universally supported. Rollbacks on schema changes are difficult. Production incidents impact sprint reliability.

How to Approach It

  1. Plan for backward compatibility: Design schema changes to not break existing application versions. New columns should be nullable initially. Old columns should remain until all application code no longer references them.
  2. Deconstruct complex changes: Break down large migrations into smaller, distinct steps. Each step should be individually deployable and reversible.
  3. Implement application tolerance: Update application code to handle both the old and new schema versions. This allows a gradual transition.
  4. Use a two-phase deployment for destructive changes: In phase one, add new schema elements. Update application code to use them. In phase two, remove obsolete schema elements. Ensure no application instances still rely on the old structure.
  5. Leverage logical replication: For major structural changes, set up logical replication. Migrate data to a new schema on a replica. Then switch applications to the new replica.
  6. Utilize online schema change tools: Employ tools like `pt-online-schema-change` or `gh-ost`. These tools perform non-blocking schema modifications. They create a copy of the table. They apply changes to the copy. They then swap the original and new tables.
  7. Version control migrations: Treat database migrations as code. Store them in version control. Automate their deployment through CI/CD pipelines.
  8. Monitor during migration: Observe application error rates, database locking, and performance metrics. These provide early warnings of issues.
  9. Prepare for rollback: Have a defined rollback plan. This includes reversion scripts or snapshots. Ensure data consistency can be maintained if a rollback is necessary.

Practical Example

A product required adding a new `email_verified_at` column to a `users` table. This column tracks user email verification timestamps. The existing `users` table had 50 million rows. A direct `ALTER TABLE ADD COLUMN` operation would incur significant locking. This would cause downtime for user authentication. The team used a three-step process. First, they deployed a migration to add the `email_verified_at` column as nullable. This step completed quickly without locking. Application code still wrote to the existing `email_verified` boolean column. The application was updated next. This new code started populating `email_verified_at` for new verifications. It also read from `email_verified_at` preferentially. It fell back to `email_verified` if `email_verified_at` was null. Then, a background job backfilled `email_verified_at` for existing users. It read `email_verified` and set `email_verified_at` accordingly. Once the backfill completed and all application instances were updated, a final migration dropped the `email_verified` column. This dropped column was no longer referenced by any running application code. This phased approach ensured continuous service availability. It never blocked user operations. Estimating development timelines includes such phased rollouts.

Common Mistakes

Assuming a direct `ALTER TABLE` is always acceptable. This often leads to prolonged table locks. These locks block reads and writes. This creates direct downtime. Insufficient testing of migration scripts is another mistake. Untested scripts can corrupt data or fail midway. This leaves the database in an inconsistent state. Not planning for rollback is a critical error. Without a defined rollback strategy, recovery from a failed migration becomes complex and time-consuming. Deploying application code that expects the new schema before the migration is applied is common. This causes immediate application errors. Not monitoring database performance and application health during the migration often delays incident detection. This prolongs downtime if issues occur. Over-scoping initial MVP features ignores these complexities. Identifying over-scoped MVPs is crucial.

Key Takeaways

  • Plan all schema changes for backward compatibility.
  • Use phased deployments for complex or destructive changes.
  • Update application code to support both schema versions.
  • Employ online schema change tools for large tables.
  • Always define and test a complete rollback strategy.

Related: how we help founders build products