Registering Database Migrations in Laravel Packages
When a Laravel package needs its own database tables, its maintainers must decide how the host application will find the package’s migration…
When you maintain a Laravel package, a breaking change is an update that makes package users change their code or configuration to keep their integration working. Renaming a public method or removing a configuration key can break an integration. A change to documented behavior can do the same.
Use Semantic Versioning, or SemVer, to tell users how much a release changes. In the MAJOR.MINOR.PATCH format, a major release marks an incompatible change. A minor release adds features that work with existing code, while a patch release fixes bugs without breaking the existing public interface. Pair the version number with clear notice: deprecate old interfaces when there is time, explain how to migrate, and ship necessary changes in a major release instead of delaying them indefinitely.
The package’s documented interface includes the methods and classes users call. It also includes configuration they publish or edit, along with behavior they rely on. Treat that interface as the package’s public contract. If users must change it to install a release, increment the major version. If the change keeps existing code working, use a minor version for a feature or a patch version for a fix, following SemVer’s versioning rules.
For example, adding an optional configuration setting is generally backward-compatible. Removing an existing setting or renaming a method requires users to make a change, so it belongs in a major release. A bug fix also deserves scrutiny when it changes behavior users had come to depend on: describe that impact and choose the version based on whether existing integrations still work.
Make the package’s Composer version requirements and release notes agree about which versions the release supports. If a release changes the supported Laravel versions, say so plainly and update the package’s dependency requirements. Laravel’s own upgrade guide shows how to identify dependency changes and explain the effect of each update.
A deprecation tells users that an interface is discouraged and the maintainer plans to remove it later. If the change is not urgent, introduce the replacement first, mark the old interface as deprecated, and keep it working in a compatible release. Remove it in a later major release. This gives users time and a clear path to migrate without requiring an indefinite wait.
Add a PHPDoc @deprecated annotation, a note in a PHP documentation comment, to the class, method, property, constant, or trait that will be removed. When users run PHPStan with the relevant deprecation rule, the PHPStan deprecation rules report uses of code marked with the annotation. The warning helps users when it names the replacement or links to migration instructions. Without a next step, users have to guess what to do.
A deprecation notice should not block necessary work. If an interface creates a security risk or prevents a required correction, explain the risk and release the fix with the appropriate major-version signal. Do not keep unsafe behavior just to meet a preferred deprecation interval. When the old and new interfaces can coexist safely, a deprecation release gives users notice before the removal.
A changelog records what changed; upgrade notes explain what users need to do. For every breaking change, name the affected interface and describe what changes for users. Then give the replacement or migration steps. If a configuration key changes, say which key to replace and where users set it. If a method changes, show the old and new usage when a short example makes the migration clearer.
Organize the release notes around what users need to change, not implementation details. Laravel’s upgrade guide uses impact ratings and before-and-after examples to help readers understand and apply changes. Package maintainers can use the same approach by stating who is affected and what they need to do. Framework-specific impact ratings are not required for packages.
If a release includes several changes or requires multiple migration steps, keep the changelog separate from a detailed migration guide. Users should be able to scan the changelog for additions, changes, deprecations, fixes, removals, and security updates. The guide should explain how to migrate. The Keep a Changelog format uses those categories and an Unreleased section that becomes a versioned release. Make each entry specific enough for users to tell whether it applies to their code.
Tell users about the change when you announce it and again when you publish the major release. Include deprecations in the release notes for the compatible release that introduces them, and mention the planned removal in the upgrade documentation. When you publish the major release, repeat the warning and migration steps so users who missed the earlier notice know what to do.
Before release, check which changes affect compatibility. Review changes to the package’s public API, the methods and classes users call, and test the affected behavior with representative Laravel integrations. Checks that compare APIs, contract tests that verify expected interactions, and functional tests can all detect breaking changes. Apply them to the parts of the package users rely on instead of relying only on a passing internal test suite (API breaking-change testing methods).
Do not let a long notice period block a necessary fix. If the change can wait safely, give users a compatible release that deprecates the old interface and explains how to migrate. If the change cannot wait, ship the correction as a major release, explain why the old behavior had to change, and give users the steps to upgrade. Users need enough information to decide what to do; a warning that postpones an essential repair indefinitely does not help them.
Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.
Take a look at vroni.com