graviton/mongodb-migrations-bundle
A Laravel bundle that adds MongoDB-aware migration support, letting you version, run, and roll back database changes through familiar artisan-style workflows. Simplifies schema and index management for MongoDB-backed apps while keeping migrations organized and repeatable.
This is a Symfony bundle (Symfony MongoDBMigrationsBundle), not a Laravel package — there is no service provider, no php artisan, and nothing that will autoload under a Laravel app. If you're coming from Laravel, read the "Gotchas" section first; the practical takeaway is that you'd adopt the underlying migrations library (anti-social/mongodb-migrations) directly rather than this bundle.
For the Symfony case, the minimal path is:
composer require libgraviton/mongodb-migrations-bundle plus ext-mongodb and mongodb/mongodb. Expect Composer to fight you on Symfony version constraints — this bundle was built for the Symfony 3/4 era (see Gotchas).config/bundles.php (Flex usually does this for you), then add config/packages/mongodb_migrations.yaml.vendor/libgraviton/mongodb-migrations-bundle/ and look at (a) the console command list and (b) the abstract migration base class. The signature of up()/down() is the one thing you must get right, and it differs between the raw-driver and ODM flavours of the underlying library (MongoDB\Database vs DocumentManager).Your first use case should be the smallest possible: a migration that creates an index you know is missing.
mongodb:migrations:generate # scaffolds a timestamped class
mongodb:migrations:status # shows applied vs. pending
mongodb:migrations:migrate # runs pending migrations in order
mongodb:migrations:execute <version> --down # targeted rollback
The migration class is a script, not a service. Extend the bundle's abstract migration and implement up()/down(). Don't expect constructor autowiring — migrations are instantiated from a class name by a factory. Take the Database/DocumentManager handle you're given in the callback and build whatever repositories you need inside up(), or expose a small static service locator if the bundle supports container injection.
Write idempotent migrations. MongoDB has no IF NOT EXISTS for most operations and no transactional DDL. The house pattern is to list collections/indexes first, then act:
public function up($db): void
{
$name = $db->listCollectionNames(['filter' => ['name' => 'users']])->toArray();
if ($name === []) { $db->createCollection('users'); }
$db->selectCollection('users')->createIndex(['email' => 1], ['unique' => true, 'name' => 'uniq_email']);
}
Index names should always be explicit, so a re-run reuses the same name instead of creating a duplicate with an auto-generated one.
Backfills: batch, checkpoint, and make them re-runnable. updateMany over a large collection will blow past the driver timeout. Loop in limit-sized pages keyed on _id (or on a migrated: false flag), and write progress so a killed deploy can resume. Never assume a migration ran to completion just because it started.
Split schema and data migrations. Version-tracking collections drift; keeping collection/index changes in one migration and data transforms in the next lets you re-run the data step safely after fixing a bug.
Deploy integration. Put mongodb:migrations:status in the pre-deploy check and mongodb:migrations:migrate after artifact upload but before the new app code goes live. Run migrations from exactly one box — see the locking note below. Keep a dedicated migrations collection per environment/database so staging and production never share a version ledger.
Testing. Point the bundle at an ephemeral database in a test kernel, run migrate, assert on the resulting collections/indexes, then migrate down to the base and assert you're clean. Most down() methods in this ecosystem are never executed in production, so tests are the only thing keeping them honest.
anti-social/mongodb-migrations with a custom Artisan command wrapping it — the effort is small and you avoid dragging a Symfony bundle (and its symfony/* constraints) into your composer.json.symfony/framework-bundle: ^3|^4. Installing on Symfony 6/7 typically requires a composer.json conflict override or a fork — decide early whether that's acceptable.migrate concurrently can apply the same migration twice. Add an external advisory lock (Redis/DB flag) around the deploy step; the bundle won't do it for you.schema:update, nothing here tells you what's missing. Migrations are hand-written and unverified — the ledger only records what you claimed to do. Audit drift separately.down() is frequently untested or unimplemented. The pragmatic stance for production is forward-only migrations: fix mistakes with a new migration rather than reverting, and treat execute --down as a dev-only tool.migrate records versions only on success, depending on config) to see what the tool believes happened, then reconcile by hand. There is no transaction to roll back.services.yaml rather than editing vendor code, and keep a note of which service IDs you touched so an upgrade doesn't blindside you.How can I help you explore Laravel packages today?