When to Release a New Major Package Version
Laravel package maintainers should release a new major version when a change breaks something they promised users would keep working. Those promises…
When you maintain a PHP package that integrates with Laravel, users need to know which PHP and Laravel versions work together with your package. A support matrix lays out those combinations. Each cell should reflect three separate facts: whether Composer allows installation, whether you promise to support the combination, and whether your continuous integration (CI) tests it.
Composer is PHP’s dependency manager. Its version requirements determine which PHP and Laravel versions can be installed together, but they do not prove that your package works at runtime. Build your matrix from those requirements and test the combinations that support your maintenance promise. Update the constraints, CI jobs, and documentation together.
A package’s composer.json declares which PHP versions and dependencies Composer will accept. These requirements show which versions can appear in the matrix. A package that requires ^12.0 of Laravel, for example, excludes Laravel 13 even if its code happens to work with that release.
A package can allow users to install a combination without promising to fix problems for it. A passing CI job shows that the test suite passed in that setup, but it does not promise ongoing support.
For each PHP and Laravel pair, check whether the package’s requirements allow it, whether Composer can find compatible versions for production and test dependencies, whether your support policy covers it, and whether CI tests it. Declare required PHP extensions as well as PHP itself: Composer checks declared platform requirements, while an omitted extension requirement can allow installation to succeed before the package fails at runtime. See Composer’s guidance on platform dependencies and version constraints.
The package’s dependency model matters too. Some packages depend on laravel/framework; others depend on individual Illuminate components. Set constraints that match the dependencies your code actually uses. Laravel recommends major-specific framework constraints because a new major release can introduce breaking changes. Its release guidance uses ^13.0 as an example.
A full Cartesian matrix tests every pair formed by the listed PHP and Laravel versions. If you list four PHP versions and two Laravel versions, that approach creates eight jobs, including pairs Composer may be unable to install or that fall outside your support policy. GitHub Actions supports explicit include rows and exclude rules, so you can run selected combinations instead of every possible pair. See the GitHub Actions matrix documentation.
Start with the versions you intend to support, then check which pairs Composer can resolve. One useful strategy is to test the oldest PHP version you support that works with each Laravel line, then test the newest PHP version you support with each Laravel line you still claim to support. For the current Laravel major, test both a lower and a newer PHP version if your promise covers that breadth. Add more pairs where a dependency or API change creates a specific compatibility risk.
Maintainers choose this testing approach; Laravel and GitHub do not prescribe it. If you omit a pair, do not label it as directly tested. Record why it is excluded, especially when the exclusion comes from an upstream PHP or Laravel requirement rather than your own support decision.
As an example of the difference between a framework’s compatibility range and a package’s tested support, Laravel’s published table lists Laravel 12 with PHP 8.2 through 8.5, and Laravel 13 with PHP 8.3 through 8.5. That gives seven framework-level candidate pairs:
| PHP | Laravel 12 | Laravel 13 |
|---|---|---|
| 8.2 | Listed by Laravel | Not listed |
| 8.3 | Listed by Laravel | Listed by Laravel |
| 8.4 | Listed by Laravel | Listed by Laravel |
| 8.5 | Listed by Laravel | Listed by Laravel |
These ranges reflect Laravel’s framework compatibility as of October 16, 2026. They do not establish that a particular package supports those pairs. Package constraints and test dependencies can narrow the set.
For package integration tests, Laravel recommends Testbench, a testing tool that boots a Laravel-style application for package tests. Choose a Testbench version that matches the Laravel major version you are testing. The Testbench Core compatibility table maps Laravel 12 to Testbench Core 10.x and Laravel 13 to 11.x; check the selected releases’ PHP and dependency requirements before treating a pair as valid.
An explicit GitHub Actions matrix makes the tested pairs visible:
strategy:
fail-fast: false
matrix:
include:
- php: "8.2"
laravel: "^12.0"
testbench: "^10.0"
- php: "8.5"
laravel: "^12.0"
testbench: "^10.0"
- php: "8.3"
laravel: "^13.0"
testbench: "^11.0"
- php: "8.5"
laravel: "^13.0"
testbench: "^11.0"
These rows illustrate a selection, not a universal recommendation. Verify each one against your package’s composer.json and the specific Testbench releases you install. With fail-fast: false, GitHub Actions keeps running the other matrix jobs after one fails, so you get results for the remaining pairs in the same run. The workflow syntax reference describes this setting.
You can also test dependency-resolution extremes. By default, Composer generally selects the newest dependency versions allowed by your constraints. Run selected jobs with --prefer-lowest to check whether the package works with the oldest dependency versions your constraints allow. This tests dependency versions, not additional PHP and Laravel pairs. The laravel-permission project’s CI workflow provides an example of combining Laravel and Testbench lines with both prefer-stable and prefer-lowest modes.
Publish the support matrix in the README or compatibility documentation, and keep it consistent with composer.json and CI. Give each combination a clear status label. For example, “supported and tested” means the package promises support and CI exercises that pair. “Supported, not directly tested” means the package includes it in its promise without a dedicated CI job; explain the basis for that claim. Use “unverified” when you lack enough evidence to make a compatibility claim.
Include the date the matrix was last reviewed, the relevant PHP and Laravel constraints, and the CI workflow that tests the stated combinations. Note excluded pairs and the reason for each exclusion. If support for a branch has a different scope for security fixes and ordinary bug fixes, say so. These labels are a documentation convention, not a standard defined by Composer or Laravel.
Laravel says it releases major framework versions annually, approximately in the first quarter, and publishes separate bug-fix and security-fix periods for each major. Use those dates as prompts to review your package’s matrix, not as automatic deadlines for dropping older versions. PHP has a separate support lifecycle, so check the PHP supported-versions schedule as well.
Before adding a new Laravel major to your support promise, check its framework and Testbench compatibility, resolve the package’s dependencies, and run the relevant tests. When you commit to support the new line, update the Composer constraints, CI matrix, documentation, and release notes together. When you consider dropping an older PHP or Laravel line, decide whether users still need it and whether you can maintain it, then communicate the change before removing its CI coverage or constraints.
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