Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Migrations Organiser Laravel Package

jaybizzle/laravel-migrations-organiser

Keeps your Laravel migrations folder tidy by automatically organising migration files into subfolders while Laravel still discovers and runs them. Works with migrate, rollback and refresh, so long-running projects stay clean without changing your workflow.

View on GitHub
Deep Wiki
Context7

Getting Started

Install as a dev dependency — this is a tooling/setup package, not something that belongs in your runtime path:

composer require jaybizzle/laravel-migrations-organiser --dev

On Laravel 5.5+ the service provider is auto-discovered. On older versions, register the package's provider manually in config/app.php. Once installed, confirm the command signature before you trust docs or blog posts:

php artisan list | grep migrate
# expect something like: migrate:organise

The first real use case is a legacy project where database/migrations/ has accumulated hundreds of flat files. Run the command on a throwaway branch with a clean working tree:

git checkout -b chore/organise-migrations
php artisan migrate:organise
php artisan migrate:status   # nothing should be pending
git status                   # review the moves before committing

The command buckets each file by the date portion of its timestamp prefix (e.g. 2023_04_11_120000_create_orders_table.php → database/migrations/2023_04_11/…) and rewrites the migration column in the migrations table to match the new relative path. That second half is the important part — the file move alone is trivial, the table rewrite is what keeps migrate:status and rollbacks sane.

Implementation Patterns

One-time cleanup, then leave it installed. The common pattern is: run it once on a legacy app, commit the moves as a single rename-only commit, and keep the package around for occasional re-runs when a folder gets noisy again. There is no ongoing runtime footprint.

Team coordination workflow. The migrations table is per-database, not per-repo, so every developer's local DB (and any shared staging DB) has stale paths until the command runs there too. Two viable approaches:

  • Preferred: one person organises and commits; everyone else restores their local DB from a dump taken after the rewrite, or runs migrate:organise once on their own DB.
  • Simpler: organise, then immediately migrate:fresh --seed on every dev machine so all local state is rebuilt with the new paths.

Bucket-by-period as a hygiene routine. After the initial cleanup, run the command at the start of each quarter or before a release cut so the current year/month folder exists and new migrations aren't dumped into a flat root. It's idempotent — files already in a bucket don't move again.

Pair it with schema dumping. On Laravel 8+, once the tree is organised, php artisan schema:dump collapses everything into schema/mysql-schema.sql and lets you prune old migration files entirely. Organising first makes that pruning decision far easier because you can see the eras of the app at a glance.

CI assertion. Add a job that runs migrate:fresh followed by migrate:status --pending and fails on non-empty output. This catches the classic failure where a migration file was moved by hand (or by a bad merge) without the table being updated.

Scoped migrations. Once files are bucketed, you can run subsets during debugging:

php artisan migrate --path=database/migrations/2024_01_15

Useful for re-running one day's worth of work against a partially-migrated local DB.

Gotchas and Tips

  • It mutates your database, not just your filesystem. Dump first (php artisan db:dump if you use spatie/laravel-db-snapshots, otherwise mysqldump/pg_dump). If the command dies halfway you'll have a half-organised tree and a half-rewritten migrations table.
  • Never move migration files by hand afterwards. Laravel identifies a migration by its path relative to database/migrations; the migrations table stores that same string. A manual mv makes every moved migration look "not run" and a subsequent migrate will explode on duplicate tables/columns.
  • Timestamp prefix is the contract. Files without a YYYY_MM_DD_HHMMSS_ prefix (hand-rolled, renamed, or generated by odd tooling) may not bucket correctly. Test on a copy of the directory first if your project has any unusual filenames.
  • Duplicate timestamps happen. Multiple migrations generated in the same second, or copied from older projects, sort unpredictably. Check for collisions before organising — batch ordering after the move will be identical, but humans reading the tree will be confused.
  • Git will show renames, not copies, but only if the content is byte-identical. Do the organise in a commit with zero content edits so git log --follow survives. git status may briefly show delete/add until you git add -A.
  • Batch rollbacks still work — conditionally. migrate:rollback resolves each migration by the name in the table, so it follows the new paths fine. It breaks the moment the table and the filesystem disagree, which is the failure mode described above.
  • Config, if present. Check vendor/jaybizzle/laravel-migrations-organiser/config/ and php artisan vendor:publish — the folder-depth/format (single YYYY_MM_DD level vs. nested year/month) is the kind of thing this package exposes, and defaults vary between versions. Verify on your installed version rather than assuming.
  • --path directories outside database/migrations are almost certainly ignored. The command targets the default migrations directory. Custom migration paths (module packages, app/Domain/*/Database/Migrations) need to be organised separately or handled by a small custom command.
  • Production safety. Don't wire this into a deploy script. Run it locally, commit the result, and let production deploy normally — the production migrations table already has the paths it recorded when migrations ran, and rewriting them mid-deploy is a needless risk.
  • Extension point: copy the command. The package is a few hundred lines at most. If you want a different bucketing scheme (by major app version, by quarter, by feature), the cleanest route is to copy the command into app/Console/Commands and adapt the date-parsing logic rather than fighting the package's config.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console