discourse-migration

Guides writing and reviewing zero-downtime Rails database migrations for Discourse.

47.8k|9.0k|Updated Jan 12, 2013
One-click install
npx skills add https://github.com/discourse/discourse --skill discourse-migration
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: discourse-migration
Source: https://github.com/discourse/discourse/tree/main/.skills/discourse-migration
Command: npx skills add https://github.com/discourse/discourse --skill discourse-migration

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve?

Discourse runs zero-downtime deployments, so a poorly written database migration can break production, fail SafeMigrate checks, or silently lose data on fresh installs. This Skill encodes the full set of conventions for writing safe migrations across db/migrate and db/post_migrate.

Core Features & Use Cases

  • Migration placement and generation: Enforces the pre-deploy (db/migrate) vs post-deploy (db/post_migrate) split and requires generator-created timestamps instead of hand-written ones.
  • Safe schema changes: Provides multi-step patterns for dropping or renaming columns and tables using Migration::ColumnDropper and Migration::TableDropper, plus concurrent indexing rules.
  • Data migration discipline: Covers batched backfills with disable_ddl_transaction!, avoiding application code in migrations, and gating inserts on Migration::Helpers.existing_site? so fresh installs stay clean.
  • Use Case: When asked to remove a deprecated column, the Skill walks through marking it readonly, adding ignored_columns, dropping it in a post-deploy migration, and regenerating structure.sql and annotations.

Quick Start

Review my new migration in db/migrate and tell me whether it follows Discourse's zero-downtime migration rules.

Frequently Asked Questions about discourse-migration

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I safely drop a column in a Discourse migration?

Dropping a column is a multi-step process: first mark it readonly with Migration::ColumnDropper.mark_readonly in a regular migration, add it to the model's ignored_columns, then drop it with Migration::ColumnDropper.execute_drop in a post-deploy migration. Remove the ignored_columns entry after the post-deploy migration is promoted.

What is the difference between db/migrate and db/post_migrate in Discourse?

db/migrate runs pre-deploy and is guarded by SafeMigrate, which blocks dropping or renaming tables and columns. db/post_migrate runs post-deploy with no safety restrictions, so all destructive operations belong there.

Why does SafeMigrate raise Discourse::InvalidMigration?

SafeMigrate blocks unsafe operations in db/migrate, such as dropping or renaming tables and columns, or creating concurrent indexes without first dropping existing ones. It is a dev/test guard only and is disabled in production.

Can I use SiteSetting or models inside a Discourse migration?

No, application code must never be called in migrations because it breaks when code changes later. Query the database directly with execute or DB.query instead, for example reading site_settings rows by name.

Does Discourse use foreign keys in migrations?

Discourse mostly does not use foreign keys; referential integrity is enforced by application logic and the EnsureDbConsistency scheduled job. Foreign keys are only added selectively for critical relationships like uploads and security keys.

When should I use disable_ddl_transaction! in a migration?

Use it only for operations that cannot run inside a transaction: concurrent index creation and batched data backfills. Keep such migrations limited to that single operation, since other schema changes would autocommit and leave the schema half-migrated on failure.