From symfony-skills
Generates, reviews, and manages Doctrine migrations in Symfony, including schema diffs, reversible migrations, and safe zero-downtime changes.
How this skill is triggered — by the user, by Claude, or both
Slash command
/symfony-skills:doctrine-migrationsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
After changing entity mapping, **generate** the migration from the diff, then review it:
After changing entity mapping, generate the migration from the diff, then review it:
php bin/console make:migration # diffs entities vs DB, scaffolds up()/down()
php bin/console doctrine:migrations:migrate
Never edit the schema with doctrine:schema:update --force outside local throwaway work — it bypasses migration history. Always review the generated SQL before committing; the diff tool sometimes proposes destructive or reordering changes you didn't intend.
final class Version20260620120000 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add status column to orders and index it';
}
public function up(Schema $schema): void
{
$this->addSql("ALTER TABLE orders ADD status VARCHAR(20) NOT NULL DEFAULT 'pending'");
$this->addSql('CREATE INDEX idx_orders_status ON orders (status)');
}
public function down(Schema $schema): void
{
$this->addSql('DROP INDEX idx_orders_status');
$this->addSql('ALTER TABLE orders DROP status');
}
}
down() must reverse up() exactly — don't leave it empty or throw. A migration you can't roll back is a deploy you can't undo.When the app is running during deploy, schema changes must be backward compatible with the currently deployed code.
| Change | Safe? | Do this |
|---|---|---|
| Add nullable column | ✅ | Single migration |
| Add NOT NULL column | ⚠️ | Add nullable → backfill → set NOT NULL (3 steps, often 2 deploys) |
| Rename column | ❌ | Add new → copy → deploy code using new → drop old |
| Drop column | ⚠️ | Deploy code that stops using it first, then drop |
| Add index on large table | ⚠️ | CREATE INDEX CONCURRENTLY (Postgres) — outside a transaction |
// Postgres concurrent index — must run outside the migration's wrapping transaction
public function up(Schema $schema): void
{
$this->addSql('CREATE INDEX CONCURRENTLY idx_orders_created_at ON orders (created_at)');
}
public function isTransactional(): bool
{
return false; // CONCURRENTLY can't run inside a transaction
}
The expand/contract pattern: expand the schema (additive, both old and new code work), deploy code, then contract (remove the old) in a later migration.
Transforming rows belongs in up() too, but keep it set-based SQL, not entity hydration (the entity classes may not match the historical schema):
public function up(Schema $schema): void
{
$this->addSql("UPDATE orders SET status = 'pending' WHERE status IS NULL");
$this->addSql('ALTER TABLE orders ALTER COLUMN status SET NOT NULL');
}
Don't use App\Entity\Order inside a migration — entities evolve, migrations are frozen in time. For heavy backfills that can't be one statement, prefer a separate idempotent console command run during deploy.
up() then down() then up() runs clean locally before pushing.getDescription()), since the class name is just a timestamp.make:migration would produce a non-empty diff (schema and entities are out of sync).php bin/console doctrine:migrations:migrate --dry-run # print SQL without executing
php bin/console doctrine:schema:validate # entities ⇄ DB in sync?
doctrine:schema:update --force instead of generating a migration — always use make:migration + migrate.down() empty or throwing — make it reverse up().NOT NULL column with no default to a populated table — add nullable, backfill, then enforce NOT NULL.CONCURRENTLY (+ isTransactional(): false) — it locks the table.npx claudepluginhub fatonh/symfony-skills --plugin symfony-skillsCreates and manages Doctrine migrations (lib 4.x) for schema versioning, handling dependencies, rollbacks, and production deployment in Symfony projects.
Generates safe, reversible database migrations from schema diffs and model changes for PostgreSQL, MySQL, Prisma, Django, Rails, Laravel.
Guides safe, reversible database schema changes and data migrations with blast radius analysis, migration patterns, and safety checks for PostgreSQL, MySQL, and ORMs.