A database migration is a versioned change to a database schema: adding a table, renaming a column, or creating an index. Migrations let a schema evolve in a known order, so every environment ends up in the same state.
How migrations work
Each migration is a file with a version and an instruction. The migration tool keeps a record of which versions have already run in the database. On each run, it applies the missing ones, in order, and records each one as it finishes.
That record is what makes migrations repeatable. Running the tool twice does nothing the second time.
Where they should run
A common mistake is to run migrations inside the application's startup. That causes three problems:
- Every restart runs the check, which is slow and noisy.
- Several instances can run the same migration at once, which can corrupt the schema or fail halfway.
- The application starts before the schema is ready, so the first requests fail in confusing ways.
A better pattern is a separate migration step. It runs once, after the database accepts connections and before the application starts. Only then does the application begin serving traffic.
TDK CLI follows this pattern in its contributor guidance. New examples run migrations in a dedicated migrator resource, ordered after Postgres and before the API. tdk doctor warns when a backend or worker runs a migration from its start script, Dockerfile command, or entrypoint.
Writing safe migrations
- Make changes backward compatible. Add a new column before the code uses it, and remove the old one only after nothing reads it.
- Keep each migration small. A small change is easier to review and to roll back.
- Avoid long locks on large tables. Adding an index can block writes; check how your database handles it.
- Do not edit a migration that has run. Add a new one instead. Editing it creates a different history on each machine.
Testing migrations
Run every migration against an empty database, and against a copy with realistic data. Check that the application works after each step. A migration that passes on an empty database can still fail on a table with millions of rows.
Rollbacks
Some migrations can be reversed, and some cannot, such as dropping data. Write the reverse migration where it makes sense. Where it does not, plan the change in two steps so that the old code keeps working until the new schema is in place.
Summary
Migrations are versioned, ordered, and recorded. Run them in their own step, once, before the application starts. Keep changes small and backward compatible, never edit an applied migration, and test against realistic data.
Top comments (0)