Rails migration: Generate, add references, and run

Rails migration workflow from generator to rollback

A Rails migration is a versioned Ruby file that changes your database schema. The usual workflow is to generate a named migration, edit its change method, run it with bin/rails db:migrate, verify the result, and roll it back when necessary.

Use the generator for predictable column and reference definitions, but inspect the generated file before applying it. Rails places migration files in db/migrate and prefixes each filename with a timestamp.

Generate a Rails migration: named command, Ruby file, and change method

Generate a named migration with a descriptive CamelCase name:

bin/rails generate migration AddStatusToOrders

Rails creates a file similar to db/migrate/20240101000000_add_status_to_orders.rb. The timestamp will differ in your project. Its contents typically look like this:

class AddStatusToOrders < ActiveRecord::Migration[7.1]
  def change
    add_column :orders, :status, :string
  end
end

The migration version in brackets follows your application’s Rails version and may be different. The change method describes the forward operation. Rails can infer the reverse operation for standard commands such as add_column, so a rollback can remove the column automatically.

Use rails generate migration to add columns

You can pass column definitions directly to rails generate migration:

bin/rails generate migration AddDetailsToUsers name:string age:integer active:boolean

This generally generates an add_column operation for each attribute in the migration file. Review and edit the file if the column needs a default, a limit, or a null constraint:

add_column :users, :name, :string, null: false
add_column :users, :age, :integer
add_column :users, :active, :boolean, default: true, null: false

Use a migration name that states both the action and the table, such as AddPublishedAtToArticles. The name helps you identify the migration in status output and deployment history; it does not replace checking the generated Ruby.

Rails migration references: index and foreign_key options

Generate a reference column with the references attribute:

bin/rails generate migration AddUserToPosts user:references

This creates a user_id column on posts through an add_reference operation. To state the intended database behavior explicitly, use:

add_reference :posts, :user, index: true, foreign_key: true

The index: true option creates an index on posts.user_id, which improves lookups and supports common association queries. The foreign_key: true option adds a database foreign-key constraint from posts.user_id to users.id, following Rails’ naming convention.

Use a custom target when the reference points to a differently named table:

add_reference :posts, :author, foreign_key: { to_table: :users }

Keep the index unless you have a specific reason not to use one. If the column must accept no missing value, add null: false only after existing rows can satisfy that constraint.

Rails migrate: run db:migrate, check status, roll back, or revise

Apply all pending migrations with:

bin/rails db:migrate

Rails records each applied migration in the database’s internal migration table. Check which files are applied or pending with:

bin/rails db:migrate:status

The status output marks migrations as up or down and shows each migration’s version and name. Confirm the change in db/schema.rb or db/structure.sql, depending on your project, and verify the new column or index in the database.

Roll back the most recent migration with:

bin/rails db:rollback STEP=1

Increase STEP to reverse several recent migrations. For a specific migration, use its version:

bin/rails db:migrate:down VERSION=20240101000000

If a migration is still down, edit its original file, run it, and check the status again. If it is already up in a shared environment, do not edit that historical file. Generate a new migration that changes or reverses the applied schema instead. On a private local branch, you can roll the migration back first, edit it, and rerun it when no other environment depends on that migration’s existing behavior.