Skip to main content
One idea at a time

A migration changes a running database

A frontend build replaces application assets. A database has existing data that must survive an application update.

A migration is a recorded change to that database structure. It might create a table, add an index, or alter a constraint. Taskboard keeps migration files with the backend so the schema can be recreated and reviewed.

The schema definition says what the application expects. The migration says how a database reaches that state. A new column in TypeScript is not available until the migration creates it.

Existing rows matter​

Imagine adding a required priority to every task. New application code always supplies it, but old tasks have no value. Adding a required column without handling those rows can fail.

A generated migration deserves review. Inspect its SQL for destructive changes, locks, defaults, and the treatment of existing records. Generation saves typing. It does not know your deployment schedule or data volume.

Do not rewrite a migration that another environment has already applied. That changes the file without changing the previous database result. Add a later migration to correct or extend the schema.

Compatibility can require several releases​

Production systems often run old and new application versions at the same time during deployment. Renaming a column can break the old version while the new version is starting.

The expand-and-contract approach separates compatibility from cleanup:

  1. Add the new structure while preserving the old structure.
  2. Deploy code that can use the new structure and backfill existing data.
  3. Stop depending on the old structure.
  4. Remove it after older application versions are gone.

This describes a production rollout pattern. Taskboard's initial migration is a fresh installation, not proof that every future change follows that pattern.

Migration safety also depends on scale. An operation that finishes immediately on an empty local database can hold a lock or scan many rows in production. Backups, restore verification, lock limits, and release sequencing belong in the operational plan.

A common mistake is calling a deployment rollback complete after restoring old application code. The database may already have changed. The old code must remain compatible, or recovery needs a separate data plan.

Why does a passing build not prove that migrations succeeded?

The compiler reads source files. It does not verify that the target PostgreSQL database has applied the same schema changes.

A migration changes durable shared state. Review both the final schema and the path existing data takes to reach it.

Read api/src/migrate.ts Read api/src/schema.ts