Skip to content

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

ProjectReleasePackagesFlaggedNot in
composer audit
abandonedsilentpinnedleft-behindold-promisestale
wallabag/wallabag2.6.15 9fd354d new210101 48%67 66%271015436
akaunting/akaunting3.3.0 67baffd new18336 20% +119 53% +116007211 +1
monicahq/monicav4.1.2 32028ce18132 18% −127 84% −172115 −125
PrestaShop/PrestaShop +2 lines9.2.0 84db6bd22831 14%31 100%4304317
phpbb/phpbbrelease-3.3.19 10356c24024 60%13 54%4101612
mautic/mautic +3 lines7.2.2 f28a012 new19623 12%21 91%2211026
grokability/snipe-itv8.8.3 621e30416719 11%18 95%151615
invoiceninja/invoiceninjav5.13.53 2e52eca new24519 8%19 100%002629
phpmyadmin/phpmyadminRELEASE_5_2_3 962857e5814 24%12 86%210920
matomo-org/matomo +1 line5.14.2 2ecd53d5514 25%13 93%142601
bagisto/bagistov2.5.0 4e7f08618112 7%12 100%000219
magento/magento22.4.9 755e34d14811 7%7 64%400115
joomla/joomla-cms +2 lines6.2.0 d7b2268899 10%8 89%201204
coollabsio/coolifyv4.5.3 70c1bcb new1688 5%8 100%020006
firefly-iii/firefly-iiiv6.7.9 ba267681327 5%7 100%011005
moodle/moodle +2 linesv5.3.0 4262229605 8%5 100%010022
appwrite/appwrite +1 line2.6.2 54581f9703 4%2 67%210000
BookStackApp/BookStackv26.09.2 6265d561133 3%3 100%000003
drupal/drupal +1 line11.4.11 76deda0662 3%2 100%010001
TYPO3/typo3 +3 linesv14.3.10 cd7b113770 0%0 0%000000
20 projects2667373 14%294 79%723410138 −12297 +1

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.

ProjectReleasePackagesFlaggedNot in
composer audit
abandonedsilentpinnedleft-behindold-promisestale
mautic/mautic 4.x4.4.13 181701c195108 55%87 81%16227288
PrestaShop/PrestaShop 1.x1.7.8.11 0a0b7c815580 52%62 78%1742321312
mautic/mautic 5.x5.2.12 ae7986a new19670 36%68 97%82282156
PrestaShop/PrestaShop 8.x8.2.8 cf4306017968 38%65 96%94327817
joomla/joomla-cms 4.x4.4.14 e2150579651 53% +148 94%141130 +123
mautic/mautic 6.x6.0.10 300c48f new19832 16%29 91%4211636
matomo-org/matomo 4.x4.16.2 df6930e4020 50%18 90%1411112
joomla/joomla-cms 5.x5.4.10 204b7439312 13% +111 92% +12024 +104
TYPO3/typo3 11.xv11.5.41 042fafc759 12%9 100%200601
appwrite/appwrite 1.x1.9.10 bb6ea62877 8%7 100%510001
drupal/drupal 10.x10.6.20 11125ec572 4%2 100%010001
TYPO3/typo3 12.xv12.4.45 b565e4c711 1%0 0%100000
TYPO3/typo3 13.xv13.4.37 05ec0d9751 1%0 0%100000
moodle/moodle 3.xv3.11.18 375a11600 0%0 0%000000
moodle/moodle 4.xv4.5.15 215f44300 0%0 0%000000
15 older lines1517461 30% +2406 88% +1802140219 +24061

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 projectCreated fromPackagesFlaggedNot in
composer audit
Advisoriesabandonedsilentpinnedleft-behindold-promisestale
Craft CMScraftcms/craft 5.8.011111 10%11 100%0020126
Pimcorepimcore/skeleton v2026.3.01929 5%8 89%0110025
Syliussylius/sylius-standard v2.3.01907 4%4 57%0300013
Statamicstatamic/statamic v6.5.21246 5%6 100%0010005
Shopwareshopware/production v6.7.16.0 new1733 2%3 100%0000003
Drupaldrupal/recommended-project 11.4.11682 3%2 100%0010001
Slimslim/slim-skeleton 4.5.0162 13%2 100%0010100
Yii 2yiisoft/yii2-app-basic 2.0.55252 8%2 100%0000110
API Platformsymfony/skeleton v8.1.99471 2%1 100%0000001
Laravellaravel/laravel v13.11.0771 1%1 100%0000001
Symfony (--webapp)symfony/skeleton v8.1.99132 −11 1%1 100%0000001
WordPress (Bedrock)roots/bedrock 1.31.8 new151 7%1 100%0000010
CakePHPcakephp/app 5.4.0200 0%0 0%0000000
Symfony (skeleton)symfony/skeleton v8.1.9910 0%0 0%0000000
TYPO3typo3/cms-base-distribution v14.3.01060 0%0 0%0000000
15 starters1297 −146 4%42 91%04603726

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

$ composer require --dev somework/lockrot
$ composer lockrot --target-php=8.4 --fail-on=silent

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.