Dependency rot in 20 PHP applications, and in 15 fresh installs¶
Every Monday lockrot 0.13.0 reads two kinds of composer.lock and reports the packages in them
that stopped being maintained: the lock the newest stable release of 20 open-source PHP
applications ships, and the lock 15 new projects get when they are created that morning
with composer create-project. This page is the last run, 2026-11-02. Nothing is installed, no script
or plugin from any package is run, and no project is contacted: the run reads lock files, then asks
Packagist and the repository host about the packages in them.
Of the 373 packages lockrot flags in these 20 applications, composer audit names 79. It says nothing at all about the other 294.
Compared with the run of 2026-10-26, across the 20 applications: left-behind 139 → 138; stale 96 → 97. Since then 7 projects moved to a new release or starter version: akaunting, coolify, invoiceninja, mautic, new-shopware, new-wordpress, wallabag.
What these applications ship¶
A project's name opens the full report lockrot wrote for it; a column heading sorts the table.
Flagged is every package with one of the six verdicts to its right — each package has exactly one,
so they add up — and is the number at the top of that report; the percentage is its share of the
lock. Not in composer audit is the flagged packages that composer audit --locked --abandoned=report (Composer 2.11.1), run on the same lock file, does not name at all — as abandoned or as carrying an advisory; its percentage is their share of the flagged ones. Composer reads the abandoned marker the lock file carries, so a package marked on Packagist after the lock was written is missed as well (what that adds up to). A small number beside a count is how far it moved since the previous run, and new marks a project
that cut a release in between; moved marks one whose newest line changed, and that row is not
compared with the previous run. Each row names the release it read and the commit that release points
at, so any number here can be
checked against the same two files lockrot read. A release rather than a branch head on purpose: a
release is what people install, and it is the only version of a project that two weeks of this page
can be compared across — the tip of a development branch moves for reasons that have nothing to do
with dependency rot.
Older lines still releasing¶
8 of the 20 applications maintain more than one release line at a time. The table above reads each one's newest line. This one reads every older line still kept beside a newer one: it has released in the last 3 years — the window lockrot gives a release branch before it calls the branch left behind (left-behind, signal S8) — and after the next line up first did, which is what makes two lines concurrent rather than one following the other. A project counts once in the totals above; these rows are not in them.
| Project | Release | Packages | Flagged | Not incomposer audit | abandoned | silent | pinned | left- | old- | stale |
|---|---|---|---|---|---|---|---|---|---|---|
| mautic/mautic 4.x | 4.4.13 181701c | 195 | 108 55% | 87 81% | 16 | 2 | 2 | 72 | 8 | 8 |
| PrestaShop/PrestaShop 1.x | 1.7.8.11 0a0b7c8 | 155 | 80 52% | 62 78% | 17 | 4 | 2 | 32 | 13 | 12 |
| mautic/mautic 5.x | 5.2.12 ae7986a new | 196 | 70 36% | 68 97% | 8 | 2 | 28 | 21 | 5 | 6 |
| PrestaShop/PrestaShop 8.x | 8.2.8 cf43060 | 179 | 68 38% | 65 96% | 9 | 4 | 3 | 27 | 8 | 17 |
| joomla/joomla-cms 4.x | 4.4.14 e215057 | 96 | 51 53% +1 | 48 94% | 14 | 1 | 1 | 30 +1 | 2 | 3 |
| mautic/mautic 6.x | 6.0.10 300c48f new | 198 | 32 16% | 29 91% | 4 | 2 | 1 | 16 | 3 | 6 |
| matomo-org/matomo 4.x | 4.16.2 df6930e | 40 | 20 50% | 18 90% | 1 | 4 | 1 | 11 | 1 | 2 |
| joomla/joomla-cms 5.x | 5.4.10 204b743 | 93 | 12 13% +1 | 11 92% +1 | 2 | 0 | 2 | 4 +1 | 0 | 4 |
| TYPO3/typo3 11.x | v11.5.41 042fafc | 75 | 9 12% | 9 100% | 2 | 0 | 0 | 6 | 0 | 1 |
| appwrite/appwrite 1.x | 1.9.10 bb6ea62 | 87 | 7 8% | 7 100% | 5 | 1 | 0 | 0 | 0 | 1 |
| drupal/drupal 10.x | 10.6.20 11125ec | 57 | 2 4% | 2 100% | 0 | 1 | 0 | 0 | 0 | 1 |
| TYPO3/typo3 12.x | v12.4.45 b565e4c | 71 | 1 1% | 0 0% | 1 | 0 | 0 | 0 | 0 | 0 |
| TYPO3/typo3 13.x | v13.4.37 05ec0d9 | 75 | 1 1% | 0 0% | 1 | 0 | 0 | 0 | 0 | 0 |
| moodle/moodle 3.x | v3.11.18 375a116 | 0 | 0 0% | 0 0% | 0 | 0 | 0 | 0 | 0 | 0 |
| moodle/moodle 4.x | v4.5.15 215f443 | 0 | 0 0% | 0 0% | 0 | 0 | 0 | 0 | 0 | 0 |
| 15 older lines | 1517 | 461 30% +2 | 406 88% +1 | 80 | 21 | 40 | 219 +2 | 40 | 61 |
Released inside the window, but with no lock file at the releases the run tried, so with no row: drupal/drupal 7.x (tried 7.103, 7.102 and 4 more).
What a new project gets today¶
A project started this morning has no history to rot in, and that is exactly why it is worth
measuring: its dependency tree is whatever the current constraints resolve to, and the answer
changes weekly without anyone touching the project. This half of the run creates each one from
scratch — composer create-project, with the starter package pinned to its newest stable version,
nothing installed and no script or plugin executed — and reads the lock file that falls out.
| New project | Created from | Packages | Flagged | Not incomposer audit | Advisories | abandoned | silent | pinned | left- | old- | stale |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Craft CMS | craftcms/craft 5.8.0 | 111 | 11 10% | 11 100% | 0 | 0 | 2 | 0 | 1 | 2 | 6 |
| Pimcore | pimcore/skeleton v2026.3.0 | 192 | 9 5% | 8 89% | 0 | 1 | 1 | 0 | 0 | 2 | 5 |
| Sylius | sylius/sylius-standard v2.3.0 | 190 | 7 4% | 4 57% | 0 | 3 | 0 | 0 | 0 | 1 | 3 |
| Statamic | statamic/statamic v6.5.2 | 124 | 6 5% | 6 100% | 0 | 0 | 1 | 0 | 0 | 0 | 5 |
| Shopware | shopware/production v6.7.16.0 new | 173 | 3 2% | 3 100% | 0 | 0 | 0 | 0 | 0 | 0 | 3 |
| Drupal | drupal/recommended-project 11.4.11 | 68 | 2 3% | 2 100% | 0 | 0 | 1 | 0 | 0 | 0 | 1 |
| Slim | slim/slim-skeleton 4.5.0 | 16 | 2 13% | 2 100% | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
| Yii 2 | yiisoft/yii2-app-basic 2.0.55 | 25 | 2 8% | 2 100% | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
| API Platform | symfony/skeleton v8.1.99 | 47 | 1 2% | 1 100% | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| Laravel | laravel/laravel v13.11.0 | 77 | 1 1% | 1 100% | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| Symfony (--webapp) | symfony/skeleton v8.1.99 | 132 −1 | 1 1% | 1 100% | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| WordPress (Bedrock) | roots/bedrock 1.31.8 new | 15 | 1 7% | 1 100% | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
| CakePHP | cakephp/app 5.4.0 | 20 | 0 0% | 0 0% | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Symfony (skeleton) | symfony/skeleton v8.1.99 | 1 | 0 0% | 0 0% | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| TYPO3 | typo3/cms-base-distribution v14.3.0 | 106 | 0 0% | 0 0% | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 15 starters | 1297 −1 | 46 4% | 42 91% | 0 | 4 | 6 | 0 | 3 | 7 | 26 |
The advisories column counts packages with a security advisory against the installed version, from
the same feed composer audit reads. It is here and not in the table above because these reports
are made with --all: every package is in the document, so an advisory on an otherwise healthy one
is visible. The applications are read without --all, where a healthy package is not a finding and
never reaches the page.
Several projects in this table cannot be in the one above, and for one reason: WordPress (Bedrock), Shopware, Sylius, TYPO3's distribution, Craft CMS, Statamic and Pimcore do not
commit a lock file to their repository. Their lock is born at create-project time, which is the only place it can be read —
and is the version their users actually run.
A verdict is an observation, not a judgement, and the two that carry most of the table say
different things. abandoned is the Packagist marker or an archived repository — someone said so.
silent is no stable release and no push to any branch for 5 years, which is lockrot's default threshold and not a law of nature: a package that encodes base64url does not need a release in 2035
either. That is what the allowlist is for, and a project that has
looked at one of these and decided it is fine can say so in its own composer.json in one line.
old-promise counts against PHP 8.4 for every project here, whatever each one actually targets,
because a column has to mean the same thing in every row. On a real project it is
--target-php that decides it.
Why these projects¶
The 20 are applications people deploy, chosen on two public signals and one hard constraint. The signals: how widely a thing is actually run, where someone else measures it — W3Techs, 21 September 2026, puts Joomla on 1.1% of all websites, Drupal on 0.6% and Adobe's Magento on 0.6% — and GitHub stars, which is what puts Coolify, Appwrite and Bagisto at the top of any list of PHP applications today.
The constraint decided more of the first table than either signal: a project has to commit
composer.json and composer.lock at a tagged release. Of the 300 most-starred PHP repositories
and a hand list of the widely-deployed ones — 109 looked at — 61 came through that filter, and
these 20 are chosen from those 61 for spread across what the applications actually do: CMS,
shop, forum, LMS, analytics, marketing, accounting, asset management, the rest.
The second table is where the rest of them turn up. WordPress (Bedrock), Shopware, Sylius, TYPO3's distribution, Craft CMS, Statamic and Pimcore commit no lock file at all — nor,
among the applications looked at, do Dolibarr, Roundcube, osTicket, SilverStripe, Contao, October,
MODX, ProcessWire and Vanilla; their dependency tree exists only once someone installs them, so
that is where it is read. The starters are the ways people actually begin a PHP project —
the framework skeletons and the vendor-recommended distributions — each pinned to its newest stable
version so the row names something checkable. The list, the reasoning and the near misses are in
data/watch/projects.json.
What moves these numbers¶
Three things, and they are worth telling apart. A project cuts a release, and the row moves because
the project moved — the release column says when that happened. A maintainer marks a package
abandoned on Packagist, and the row moves although the release did not change at all, which is the
gap this post is about and the reason
composer audit does not see most of what is here. Or lockrot learns to measure something it
skipped before, and the row moves because the tool moved; every row in
history.csv carries the release, the commit and the lockrot version that produced it
for exactly that reason.
Earlier runs¶
Every run stays readable: each one below links the reports it published, rendered with the same
lockrot renderer as this week's, from the document that run wrote. The numbers behind all of them are
in history.csv.
2026-11-02 · lockrot 0.13.0 · 50 reports · 156 abandoned, 61 silent
coolify, appwrite, appwrite-v1, bagisto, monica, firefly-iii, matomo, matomo-v4, bookstack, snipe-it, wallabag, magento2, mautic, mautic-v6, mautic-v5, mautic-v4, akaunting, invoiceninja, prestashop, prestashop-v8, prestashop-v1, moodle, moodle-v4, moodle-v3, phpmyadmin, phpbb, joomla-cms, joomla-cms-v5, joomla-cms-v4, drupal, drupal-v10, typo3, typo3-v13, typo3-v12, typo3-v11, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-10-26 · lockrot 0.13.0 · 50 reports · 156 abandoned, 61 silent
coolify, appwrite, appwrite-v1, bagisto, monica, firefly-iii, matomo, matomo-v4, bookstack, snipe-it, wallabag, magento2, mautic, mautic-v6, mautic-v5, mautic-v4, akaunting, invoiceninja, prestashop, prestashop-v8, prestashop-v1, moodle, moodle-v4, moodle-v3, phpmyadmin, phpbb, joomla-cms, joomla-cms-v5, joomla-cms-v4, drupal, drupal-v10, typo3, typo3-v13, typo3-v12, typo3-v11, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-10-21 · lockrot 0.13.0 · 50 reports · 156 abandoned, 61 silent
coolify, appwrite, appwrite-v1, bagisto, monica, firefly-iii, matomo, matomo-v4, bookstack, snipe-it, wallabag, magento2, mautic, mautic-v6, mautic-v5, mautic-v4, akaunting, invoiceninja, prestashop, prestashop-v8, prestashop-v1, moodle, moodle-v4, moodle-v3, phpmyadmin, phpbb, joomla-cms, joomla-cms-v5, joomla-cms-v4, drupal, drupal-v10, typo3, typo3-v13, typo3-v12, typo3-v11, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-10-19 · lockrot 0.13.0 · 50 reports · 155 abandoned, 61 silent
coolify, appwrite, appwrite-v1, bagisto, monica, firefly-iii, matomo, matomo-v4, bookstack, snipe-it, wallabag, magento2, mautic, mautic-v6, mautic-v5, mautic-v4, akaunting, invoiceninja, prestashop, prestashop-v8, prestashop-v1, moodle, moodle-v4, moodle-v3, phpmyadmin, phpbb, joomla-cms, joomla-cms-v5, joomla-cms-v4, drupal, drupal-v10, typo3, typo3-v13, typo3-v12, typo3-v11, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-10-12 · lockrot 0.13.0 · 50 reports · 155 abandoned, 61 silent
coolify, appwrite, appwrite-v1, bagisto, monica, firefly-iii, matomo, matomo-v4, bookstack, snipe-it, wallabag, magento2, mautic, mautic-v6, mautic-v5, mautic-v4, akaunting, invoiceninja, prestashop, prestashop-v8, prestashop-v1, moodle, moodle-v4, moodle-v3, phpmyadmin, phpbb, joomla-cms, joomla-cms-v5, joomla-cms-v4, drupal, drupal-v10, typo3, typo3-v13, typo3-v12, typo3-v11, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-10-05 · lockrot 0.13.0 · 49 reports · 151 abandoned, 60 silent
coolify, appwrite, bagisto, monica, firefly-iii, matomo, matomo-v4, bookstack, snipe-it, wallabag, magento2, mautic, mautic-v6, mautic-v5, mautic-v4, akaunting, invoiceninja, prestashop, prestashop-v8, prestashop-v1, moodle, moodle-v4, moodle-v3, phpmyadmin, phpbb, joomla-cms, joomla-cms-v5, joomla-cms-v4, drupal, drupal-v10, typo3, typo3-v13, typo3-v12, typo3-v11, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-10-01 · lockrot 0.13.0 · 49 reports · 151 abandoned, 60 silent
coolify, appwrite, bagisto, monica, firefly-iii, matomo, matomo-v4, bookstack, snipe-it, wallabag, magento2, mautic, mautic-v6, mautic-v5, mautic-v4, akaunting, invoiceninja, prestashop, prestashop-v8, prestashop-v1, moodle, moodle-v4, moodle-v3, phpmyadmin, phpbb, joomla-cms, joomla-cms-v5, joomla-cms-v4, drupal, drupal-v10, typo3, typo3-v13, typo3-v12, typo3-v11, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-09-28 · lockrot 0.12.0 · 35 reports · 76 abandoned, 40 silent
coolify, appwrite, bagisto, monica, firefly-iii, matomo, bookstack, snipe-it, wallabag, magento2, mautic, akaunting, invoiceninja, prestashop, moodle, phpmyadmin, phpbb, joomla-cms, drupal, typo3, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-09-24 · lockrot 0.12.0 · 35 reports · 76 abandoned, 40 silent
coolify, appwrite, bagisto, monica, firefly-iii, matomo, bookstack, snipe-it, wallabag, magento2, mautic, akaunting, invoiceninja, prestashop, moodle, phpmyadmin, phpbb, joomla-cms, drupal, typo3, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-09-23 · lockrot 0.11.0 · 35 reports · 76 abandoned, 40 silent
coolify, appwrite, bagisto, monica, firefly-iii, matomo, bookstack, snipe-it, wallabag, magento2, mautic, akaunting, invoiceninja, prestashop, moodle, phpmyadmin, phpbb, joomla-cms, drupal, typo3, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
2026-09-21 · lockrot 0.10.0 · 35 reports · 76 abandoned, 40 silent
coolify, appwrite, bagisto, monica, firefly-iii, matomo, bookstack, snipe-it, wallabag, magento2, mautic, akaunting, invoiceninja, prestashop, moodle, phpmyadmin, phpbb, joomla-cms, drupal, typo3, new-laravel, new-symfony, new-symfony-webapp, new-api-platform, new-drupal, new-wordpress, new-shopware, new-sylius, new-typo3, new-craft, new-statamic, new-pimcore, new-slim, new-cakephp, new-yii2
Running it on your own lock¶
The PHAR does the same without touching the lock (download and verify), and the GitHub Action is what this page runs. A project with a long list starts from a baseline and fails on what arrives next, rather than on what is already there.