Migrations and Schema
Fast recall
Quick revision
Core answer
Whether you know migrations are versioned schema-change files tracked in schema_migrations, reversible, shareable, and you never edit pushed ones.
Editing a migration that's been pushed (other devs' DBs diverge) — make a new migration to change.
Migrations: versioned Ruby files changing the DB schema. rails db:migrate applies; db/schema.rb records state; reversible; never edit pushed ones.
Interview-ready guide
Interview answer
A Rails migration is a versioned Ruby class that describes a database change such as creating a table, adding a column, or building an index. Rails records applied versions in the database, so bin/rails db:migrate executes only migrations that are still pending for that database.
The migration files are change history. db/schema.rb or db/structure.sql is a snapshot of the current database structure used for inspection and fast setup; it is not a replacement for planning the next production change. Rails updates the schema dump after migrations run.
For example, adding account_id to orders can include a reference, an index for lookup, and a database foreign key for referential integrity. Whether the column can immediately be non-null depends on existing rows and whether an older application version can still write orders without it.
Many DSL operations in change are automatically reversible. For an operation Rails cannot infer, I use reversible or explicit up and down. A rollback is not always safe for destructive changes, large data conversions, or code already deployed against the new shape, so recovery planning is wider than writing a down method.
I never edit an already shared migration to pretend history changed. I add a new migration, test a fresh schema and an upgrade path, inspect locks and runtime on production-sized data, and deploy additive changes before code that depends on them. This keeps every environment able to reach the same understood structure.
Migrations and Schema
Direct Answer
Rails migrations are ordered, versioned programs that move a database schema forward or backward; the schema dump records the current structure after those changes. Rails stores applied migration versions in the database and runs only pending migrations. Once a migration has reached a shared environment, create a new corrective migration instead of rewriting history. Add database constraints and indexes deliberately, make reversibility explicit, and design production changes so old and new application versions can overlap safely during deployment.
Deep Dive & Architecture
A migration version marks whether one database has crossed a change, not the complete state of every record. Schema changes and data backfills can have different operational needs. A small local table alteration may lock or rewrite a large production table, so row count and database capabilities belong in the migration review.
Reversibility is semantic. Rails can invert add_column, but removing the column later cannot recreate discarded values. Renaming or changing types may require application code that reads both forms during a transition. Explicit down code documents mechanics but cannot promise business data will return.
Zero-downtime changes normally expand before they contract. Add a nullable column or new table, deploy code that can work with both shapes, backfill and verify, switch reads, then enforce constraints or remove the old shape in a later release. This sequence protects requests handled by old and new processes during rollout.
Database constraints are the final shared guard because every process and script writes through the same database. Model validations improve feedback but can race and can be bypassed. A schema review therefore considers nullability, foreign keys, uniqueness, indexes, default behaviour, and how failures surface in the application.
Code Example
class AddAccountToOrders < ActiveRecord::Migration[8.1]
def change
add_reference :orders, :account,
null: true,
foreign_key: true,
index: true
end
end
# Backfill existing rows separately, deploy compatible code,
# then enforce null: false in a later reviewed migration.
Common Mistakes & Pitfalls
Editing a migration that's been pushed (other devs' DBs diverge) — make a new migration to change.
Check your understanding
Answer these without looking back at the article.
- How is a migration different from `schema.rb` or `structure.sql`?
- Why can an automatically reversible migration still lose business data?
- What does expand-and-contract protect during a rolling deployment?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.