doctrine-migrations
Skill35 starsChanged 5 months agoMITView on GitHub
Use when changing the database schema in Symfony — generating Doctrine migrations, writing reversible up()/down(), data migrations, and deploy-safe (zero-downtime) changes. Use when the task mentions migration, schema change, ALTER TABLE, or doctrine:migrations.
1 other project uses a version of this.
Adopted by
Most recently taken up by
- gerard-labs/superpowers-api-platformtheir own version, first seen Oct 13, 2026
Other versions1 project uses a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 1
- gerard-labs/superpowers-api-platform★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository16 other files it gives its agents.
- api-platform-resourcesSkill
- bundle-organizationSkill
- console-commandsSkill
- doctrine-ormSkill
- doctrine-query-optimizationSkill
- domain-driven-designSkill
- dto-and-validationSkill
- hexagonal-architectureSkill
- jwt-authenticationSkill
- layered-architectureSkill
- messenger-asyncSkill
- problem-details-rfc9457Skill
- rest-controller-conventionsSkill
- security-authenticationSkill
- testing-pyramidSkill
- transactional-patternsSkill
The file
We split this skill into the rules it gives an agent
6 rules. About 0 are common, 3 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
After changing entity mapping, generate the migration from the diff, then review it:
- Very specific: line 21
Never edit the schema with doctrine:schema:update --force outside local throwaway work — it bypasses migration history.
- Distinctive: line 49
Keep migrations immutable once merged/deployed.
- Distinctive: line 53
When the app is running during deploy, schema changes must be backward compatible with the currently deployed code.
- Very specific: line 90
Don't use App\Entity\Order inside a migration — entities evolve, migrations are frozen in time.
- Very specific: line 95
Verify up() then down() then up() runs clean locally before pushing.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Doctrine Migrations (Symfony)
Generate, don't hand-write the schema diff
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:migrateNever 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.
Anatomy of a migration
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 reverseup()exactly — don't leave it empty orthrow. A migration you can't roll back is a deploy you can't undo.- One logical change per migration — don't bundle unrelated DDL.
- Keep migrations immutable once merged/deployed. Never edit a migration that has run anywhere; write a new one.
Zero-downtime / deploy-safe changes
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.
Data migrations
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.
Conventions
- One migration file per PR that changes the schema; commit it alongside the entity change.
- Verify
up()thendown()thenup()runs clean locally before pushing. - Name migrations by what they do (via
getDescription()), since the class name is just a timestamp. - In CI, fail the build if
make:migrationwould 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?Gotchas
- Agent runs
doctrine:schema:update --forceinstead of generating a migration — always usemake:migration+migrate. - Agent leaves
down()empty or throwing — make it reverseup(). - Agent adds a
NOT NULLcolumn with no default to a populated table — add nullable, backfill, then enforce NOT NULL. - Agent edits an already-deployed migration — migrations are immutable; write a new one.
- Agent imports entity classes inside a migration — use raw SQL; entities don't match historical schemas.
- Agent renames a column in one step during a live deploy — use expand/contract.
- Agent creates an index on a big Postgres table without
CONCURRENTLY(+isTransactional(): false) — it locks the table. - Agent bundles several unrelated schema changes into one migration — keep them separate.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

