---
title: "What 3052 composer.json files tell us about the Composer plugin ecosystem"
url: https://www.exakat.io/what-3052-composer-json-files-tell-us-about-the-composer-plugin-ecosystem/
date: 2026-08-28
modified: 2026-08-28
author: "dams"
description: "What 3052 composer.json files tell us about the Composer plugin ecosystem I like to read composer.json files the way other people read tea leaves. Take enough of them and patterns..."
categories:
  - "Code auditing"
tags:
  - "composer"
image: https://www.exakat.io/wp-content/uploads/2026/08/composer.320.png
word_count: 2617
---

# What 3052 composer.json files tell us about the Composer plugin ecosystem

# What 3052 composer.json files tell us about the Composer plugin ecosystem

I like to read `composer.json` files the way other people read tea leaves. Take enough of them and patterns emerge: which packages everyone depends on, which ones are stuck two major versions behind, and what a `minimum-stability` field says about a maintainer's risk tolerance.

For this post, I pulled every `composer.json` I could find under `projects/*/code/` in my local Exakat corpus: 3285 project directories, 3054 of which actually ship a `composer.json`. Yes, I usually estimate that 2% of PHP application do not use composer.json. Not great, no bad.

I parsed all of them, and 3052 came back as valid JSON (two are broken, a separate post, maybe). Most of these projects are Composer plugins and installers: 42% declare `type: composer-plugin`, and `composer-plugin-api` shows up as a requirement in 40% of all files. So what follows is really a snapshot of the *Composer plugin ecosystem* specifically, not PHP at large: keep that in mind when you compare it to your own dependency tree.

Here's what the numbers say.

## PHP itself: how low do people set the floor

Before anything else, there's the language itself. Only **1548 of the 3052 manifests, that is 50.7%, declare a `php` constraint at all.** The other half either leaves compatibility entirely to `composer-plugin-api`, or simply doesn't say. For a plugin that's meant to install on a stranger's machine, that's a striking number of authors who never wrote down the one constraint that would actually stop it from running.

For the 1548 that do declare one, here's the floor they set, the lowest PHP minor version each constraint would still accept, whether written as `^8.1`, `>=7.4`, `~7.4` or an OR'd chain of ranges:

```
PHP 5
5.0 2 (0.1%)
5.1 2 (0.1%)
5.2 3 (0.2%)
5.3 ████████████████ 106 (6.8%)
5.4 ████████ 56 (3.6%)
5.5 █████████ 63 (4.1%)
5.6 ████████████ 82 (5.3%)

PHP 7
7.0 ████████████ 77 (5.0%)
7.1 █████████████████████ 143 (9.2%)
7.2 █████████████████ 111 (7.2%)
7.3 ███████████ 72 (4.7%)
7.4 █████████████████████████ 168 (10.9%)

PHP 8
8.0 ████████████████████ 135 (8.7%)
8.1 ██████████████████████████████ 200 (12.9%)
8.2 ████████████████████████ 158 (10.2%)
8.3 ██████████████ 92 (5.9%)
8.4 ██████████ 64 (4.1%)
8.5 ██ 13 (0.8%)
```

*Floor version implied by each project's `php` constraint, out of the 1548 manifests that declare one.*

PHP 8.1 alone is the single most common floor, for 200 projects or 12.9%, but it's not a landslide: `^7.1`, `^7.4`, `^8.0` and `^8.2` are all close behind it. Group by major and the picture is more telling: PHP 8.x floors account for 42.8% of the declared constraints, PHP 7.x for 36.9%, and PHP 5.x, a version whose last release shipped over a decade ago, still accounts for 20.3%. One in five plugins that bothers to state a PHP version at all is still willing to run on PHP 5. Or so they claim.

## The extensions people build against

2259 `ext-*` requirements, spread across 87 distinct extensions, appear in 583 composer.json: 19.1% of the corpus declares at least one. The head of the list is exactly what you'd expect from PHP core: JSON, mbstring, cURL, PDO, DOM. The tail is where it gets interesting: a long list of extensions required by exactly one project each, which is its own kind of signal about how specialized some of these extensions are.

| Extension | Projects | Share | Home |
| --------- | -------- | ----- | ---- |
| `ext-json` | 370 | 12.12% | [link](https://www.php.net/book.json) |
| `ext-mbstring` | 183 | 6.00% | [link](https://www.php.net/book.mbstring) |
| `ext-curl` | 130 | 4.26% | [link](https://www.php.net/book.curl) |
| `ext-pdo` | 116 | 3.80% | [link](https://www.php.net/book.pdo) |
| `ext-dom` | 111 | 3.64% | [link](https://www.php.net/book.dom) |
| `ext-openssl` | 94 | 3.08% | [link](https://www.php.net/book.openssl) |
| `ext-gd` | 89 | 2.92% | [link](https://www.php.net/book.image) |
| `ext-simplexml` | 86 | 2.82% | [link](https://www.php.net/book.simplexml) |
| `ext-intl` | 80 | 2.62% | [link](https://www.php.net/book.intl) |
| `ext-zip` | 77 | 2.52% | [link](https://www.php.net/book.zip) |
| `ext-fileinfo` | 74 | 2.42% | [link](https://www.php.net/book.fileinfo) |
| `ext-xml` | 67 | 2.20% | [link](https://www.php.net/book.xml) |
| `ext-iconv` | 63 | 2.06% | [link](https://www.php.net/book.iconv) |
| `ext-ctype` | 60 | 1.97% | [link](https://www.php.net/book.ctype) |
| `ext-libxml` | 54 | 1.77% | [link](https://www.php.net/book.libxml) |
| `ext-zlib` | 44 | 1.44% | [link](https://www.php.net/book.zlib) |
| `ext-tokenizer` | 36 | 1.18% | [link](https://www.php.net/book.tokenizer) |
| `ext-bcmath` | 36 | 1.18% | [link](https://www.php.net/book.bc) |
| `ext-filter` | 31 | 1.02% | [link](https://www.php.net/book.filter) |
| `ext-pcre` | 26 | 0.85% | [link](https://www.php.net/book.pcre) |
| `ext-hash` | 26 | 0.85% | [link](https://www.php.net/book.hash) |
| `ext-session` | 25 | 0.82% | [link](https://www.php.net/book.session) |
| `ext-spl` | 21 | 0.69% | [link](https://www.php.net/book.spl) |
| `ext-pdo_mysql` | 21 | 0.69% | [link](https://www.php.net/manual/en/ref.pdo-mysql.php) |
| `ext-posix` | 20 | 0.66% | [link](https://www.php.net/book.posix) |
| `ext-xmlreader` | 19 | 0.62% | [link](https://www.php.net/book.xmlreader) |
| `ext-exif` | 19 | 0.62% | [link](https://www.php.net/book.exif) |
| `ext-soap` | 18 | 0.59% | [link](https://www.php.net/book.soap) |
| `ext-sodium` | 17 | 0.56% | [link](https://www.php.net/book.sodium) |
| `ext-mysqli` | 17 | 0.56% | [link](https://www.php.net/book.mysqli) |
| `ext-redis` | 17 | 0.56% | [link](https://pecl.php.net/package/redis) |
| `ext-xmlwriter` | 15 | 0.49% | [link](https://www.php.net/book.xmlwriter) |
| `ext-reflection` | 11 | 0.36% | [link](https://www.php.net/book.reflection) |
| `ext-sockets` | 11 | 0.36% | [link](https://www.php.net/book.sockets) |
| `ext-xsl` | 11 | 0.36% | [link](https://www.php.net/book.xsl) |
| `ext-apcu` | 11 | 0.36% | [link](https://pecl.php.net/package/APCu) |
| `ext-pcntl` | 11 | 0.36% | [link](https://www.php.net/book.pcntl) |
| `ext-gettext` | 10 | 0.33% | [link](https://www.php.net/book.gettext) |
| `ext-gmp` | 10 | 0.33% | [link](https://www.php.net/book.gmp) |
| `ext-sqlite3` | 9 | 0.29% | [link](https://www.php.net/book.sqlite3) |
| `ext-imagick` | 9 | 0.29% | [link](https://pecl.php.net/package/imagick) |
| `ext-ldap` | 8 | 0.26% | [link](https://www.php.net/book.ldap) |
| `ext-phar` | 7 | 0.23% | [link](https://www.php.net/book.phar) |
| `ext-yaml` | 6 | 0.20% | [link](https://pecl.php.net/package/yaml) |
| `ext-readline` | 6 | 0.20% | [link](https://www.php.net/book.readline) |
| `ext-pgsql` | 6 | 0.20% | [link](https://www.php.net/book.pgsql) |
| `ext-pdo_sqlite` | 5 | 0.16% | [link](https://www.php.net/manual/en/ref.pdo-sqlite.php) |
| `ext-calendar` | 5 | 0.16% | [link](https://www.php.net/book.calendar) |
| `ext-zend-opcache` | 4 | 0.13% | [link](https://www.php.net/book.opcache) |
| `ext-ftp` | 4 | 0.13% | [link](https://www.php.net/book.ftp) |
| `ext-swoole` | 4 | 0.13% | [link](https://github.com/swoole/swoole-src) |
| `ext-mongodb` | 3 | 0.10% | [link](https://pecl.php.net/package/mongodb) |
| `ext-memcached` | 3 | 0.10% | [link](https://pecl.php.net/package/memcached) |
| `ext-http` | 2 | 0.07% | [link](https://pecl.php.net/package/pecl_http) |
| `ext-pdo_pgsql` | 2 | 0.07% | [link](https://www.php.net/manual/en/ref.pdo-pgsql.php) |
| `ext-amqp` | 2 | 0.07% | [link](https://pecl.php.net/package/amqp) |
| `ext-tidy` | 2 | 0.07% | [link](https://www.php.net/book.tidy) |
| `ext-mcrypt` | 2 | 0.07% | [link](https://pecl.php.net/package/mcrypt) |
| `ext-igbinary` | 2 | 0.07% | [link](https://pecl.php.net/package/igbinary) |
| `ext-gnupg` | 2 | 0.07% | [link](https://pecl.php.net/package/gnupg) |
| `ext-ffi` | 2 | 0.07% | [link](https://www.php.net/book.ffi) |
| `ext-date` | 2 | 0.07% | [link](https://www.php.net/book.datetime) |
| `ext-gearman` | 1 | 0.03% | [link](https://pecl.php.net/package/gearman) |
| `ext-rdkafka` | 1 | 0.03% | [link](https://pecl.php.net/package/rdkafka) |
| `ext-geos` | 1 | 0.03% | [link](https://github.com/libgeos/php-geos) |
| `ext-lua` | 1 | 0.03% | [link](https://github.com/laruence/php-lua) |
| `ext-bz2` | 1 | 0.03% | [link](https://www.php.net/book.bzip2) |
| `ext-dba` | 1 | 0.03% | [link](https://www.php.net/book.dba) |
| `ext-mustache` | 1 | 0.03% | [link](https://github.com/jbboehr/php-mustache) |
| `ext-tideways` | 1 | 0.03% | [link](https://github.com/tideways/php-xhprof-extension) |
| `ext-wikidiff2` | 1 | 0.03% | [link](https://github.com/wikimedia/mediawiki-php-wikidiff2) |
| `ext-imap` | 1 | 0.03% | [link](https://www.php.net/book.imap) |
| `ext-sysvmsg` | 1 | 0.03% | [link](https://www.php.net/book.sem) |
| `ext-sysvsem` | 1 | 0.03% | [link](https://www.php.net/book.sem) |
| `ext-sysvshm` | 1 | 0.03% | [link](https://www.php.net/book.sem) |
| `ext-parallel` | 1 | 0.03% | [link](https://pecl.php.net/package/parallel) |
| `ext-shmop` | 1 | 0.03% | [link](https://www.php.net/book.shmop) |
| `ext-phalcon` | 1 | 0.03% | [link](https://phalcon.io/) |
| `ext-openswoole` | 1 | 0.03% | [link](https://openswoole.com/) |
| `ext-chunkutils2` | 1 | 0.03% | [link](https://github.com/pmmp/ext-chunkutils2) |
| `ext-crypto` | 1 | 0.03% | [link](https://github.com/bukka/php-crypto) |
| `ext-encoding` | 1 | 0.03% | — |
| `ext-leveldb` | 1 | 0.03% | [link](https://pecl.php.net/package/leveldb) |
| `ext-morton` | 1 | 0.03% | [link](https://github.com/pmmp/ext-morton) |
| `ext-pmmpthread` | 1 | 0.03% | [link](https://github.com/pmmp/ext-pmmpthread) |
| `ext-mysqlnd` | 1 | 0.03% | [link](https://www.php.net/book.mysqlnd) |
| `ext-maxminddb` | 1 | 0.03% | [link](https://pecl.php.net/package/maxminddb) |

*Extension names normalized to lowercase (a handful of manifests write `ext-SPL` or `ext-PDO`); links go to the PHP manual for bundled extensions and to PECL or the project's own repository for everything else. `ext-encoding` is left unlinked: I couldn't confidently confirm what current package it maps to.*

The long tail tells its own story: `ext-swoole` and `ext-openswoole` for async runtimes, `ext-chunkutils2`/`ext-morton`/`ext-pmmpthread` from the PocketMine-MP Minecraft-server project, `ext-geos` for geospatial computation, `ext-wikidiff2` straight out of MediaWiki, `ext-phalcon` for a framework that ships as a compiled extension rather than a library. None of these are things you'd predict from a generic "PHP ecosystem" survey. They only show up because this corpus is Composer plugins specifically, each one built to solve one real, narrow problem.

That's PHP and its extensions accounted for. What's left is the actual software. They are the libraries, frameworks and tools people install on top of the platform to build their plugins.

## Top 50 most required packages

19945 `require` entries across the corpus, spread over 5707 distinct package names: this time, real Packagist packages only, with `php`, `ext-*`, `lib-*` and `composer-plugin-api`/`composer-runtime-api` stripped out. Most of that 5707 is one-off dependencies used by a single plugin. Here's the top of the distribution, with the most frequent components:

| # | Package | Projects | Share |
| --- | ------- | -------- | ----- |
| 1 | [symfony/console](https://packagist.org/packages/symfony/console) | 215 | 7.0% |
| 2 | [symfony/yaml](https://packagist.org/packages/symfony/yaml) | 182 | 6.0% |
| 3 | [guzzlehttp/guzzle](https://packagist.org/packages/guzzlehttp/guzzle) | 176 | 5.8% |
| 4 | [psr/log](https://packagist.org/packages/psr/log) | 138 | 4.5% |
| 5 | [symfony/filesystem](https://packagist.org/packages/symfony/filesystem) | 137 | 4.5% |
| 6 | [symfony/finder](https://packagist.org/packages/symfony/finder) | 130 | 4.3% |
| 7 | [symfony/process](https://packagist.org/packages/symfony/process) | 115 | 3.8% |
| 8 | [laravel/framework](https://packagist.org/packages/laravel/framework) | 104 | 3.4% |
| 9 | [twig/twig](https://packagist.org/packages/twig/twig) | 93 | 3.0% |
| 10 | [monolog/monolog](https://packagist.org/packages/monolog/monolog) | 92 | 3.0% |
| 11 | [composer/installers](https://packagist.org/packages/composer/installers) | 89 | 2.9% |
| 12 | [composer/composer](https://packagist.org/packages/composer/composer) | 88 | 2.9% |
| 13 | [doctrine/dbal](https://packagist.org/packages/doctrine/dbal) | 84 | 2.8% |
| 14 | [symfony/event-dispatcher](https://packagist.org/packages/symfony/event-dispatcher) | 76 | 2.5% |
| 15 | [laravel/tinker](https://packagist.org/packages/laravel/tinker) | 76 | 2.5% |
| 16 | [psr/container](https://packagist.org/packages/psr/container) | 76 | 2.5% |
| 17 | [psr/http-message](https://packagist.org/packages/psr/http-message) | 75 | 2.5% |
| 18 | [nikic/php-parser](https://packagist.org/packages/nikic/php-parser) | 75 | 2.5% |
| 19 | [vlucas/phpdotenv](https://packagist.org/packages/vlucas/phpdotenv) | 73 | 2.4% |
| 20 | [phpmailer/phpmailer](https://packagist.org/packages/phpmailer/phpmailer) | 68 | 2.2% |
| 21 | [symfony/config](https://packagist.org/packages/symfony/config) | 63 | 2.1% |
| 22 | [symfony/http-client](https://packagist.org/packages/symfony/http-client) | 62 | 2.0% |
| 23 | [symfony/dependency-injection](https://packagist.org/packages/symfony/dependency-injection) | 60 | 2.0% |
| 24 | [symfony/http-foundation](https://packagist.org/packages/symfony/http-foundation) | 60 | 2.0% |
| 25 | [symfony/mailer](https://packagist.org/packages/symfony/mailer) | 57 | 1.9% |
| 26 | [doctrine/orm](https://packagist.org/packages/doctrine/orm) | 57 | 1.9% |
| 27 | [symfony/validator](https://packagist.org/packages/symfony/validator) | 56 | 1.8% |
| 28 | [ramsey/uuid](https://packagist.org/packages/ramsey/uuid) | 53 | 1.7% |
| 29 | [symfony/cache](https://packagist.org/packages/symfony/cache) | 51 | 1.7% |
| 30 | [symfony/dotenv](https://packagist.org/packages/symfony/dotenv) | 51 | 1.7% |
| 31 | [composer/semver](https://packagist.org/packages/composer/semver) | 49 | 1.6% |
| 32 | [psr/simple-cache](https://packagist.org/packages/psr/simple-cache) | 49 | 1.6% |
| 33 | [ezyang/htmlpurifier](https://packagist.org/packages/ezyang/htmlpurifier) | 46 | 1.5% |
| 34 | [illuminate/support](https://packagist.org/packages/illuminate/support) | 46 | 1.5% |
| 35 | [symfony/property-access](https://packagist.org/packages/symfony/property-access) | 44 | 1.4% |
| 36 | [league/flysystem](https://packagist.org/packages/league/flysystem) | 43 | 1.4% |
| 37 | [symfony/framework-bundle](https://packagist.org/packages/symfony/framework-bundle) | 43 | 1.4% |
| 38 | [psr/http-client](https://packagist.org/packages/psr/http-client) | 43 | 1.4% |
| 39 | [nyholm/psr7](https://packagist.org/packages/nyholm/psr7) | 41 | 1.3% |
| 40 | [symfony/translation](https://packagist.org/packages/symfony/translation) | 41 | 1.3% |
| 41 | [symfony/expression-language](https://packagist.org/packages/symfony/expression-language) | 40 | 1.3% |
| 42 | [symfony/var-dumper](https://packagist.org/packages/symfony/var-dumper) | 40 | 1.3% |
| 43 | [league/flysystem-aws-s3-v3](https://packagist.org/packages/league/flysystem-aws-s3-v3) | 40 | 1.3% |
| 44 | [doctrine/doctrine-bundle](https://packagist.org/packages/doctrine/doctrine-bundle) | 39 | 1.3% |
| 45 | [predis/predis](https://packagist.org/packages/predis/predis) | 38 | 1.2% |
| 46 | [erusev/parsedown](https://packagist.org/packages/erusev/parsedown) | 38 | 1.2% |
| 47 | [symfony/http-kernel](https://packagist.org/packages/symfony/http-kernel) | 38 | 1.2% |
| 48 | [symfony/mime](https://packagist.org/packages/symfony/mime) | 38 | 1.2% |
| 49 | [symfony/twig-bundle](https://packagist.org/packages/symfony/twig-bundle) | 38 | 1.2% |
| 50 | [psr/http-factory](https://packagist.org/packages/psr/http-factory) | 38 | 1.2% |

Symfony components own this list: 24 of the top 50 are `symfony/*`. Guzzle, Monolog, Doctrine and the PSR interfaces fill most of the rest. Laravel shows up too, with `laravel/framework`, `laravel/tinker`, `illuminate/support`, a reminder that plenty of these "Composer plugins" are actually Laravel packages that happen to also ship an installer.

## Top 50 most required dev packages

require-dev is a much smaller and more concentrated world: 8474 entries, 1385 distinct packages, and a very predictable top of the table.

| # | Package | Projects | Share |
| --- | ------- | -------- | ----- |
| 1 | [phpunit/phpunit](https://packagist.org/packages/phpunit/phpunit) | 1043 | 34.2% |
| 2 | [composer/composer](https://packagist.org/packages/composer/composer) | 810 | 26.5% |
| 3 | [phpstan/phpstan](https://packagist.org/packages/phpstan/phpstan) | 373 | 12.2% |
| 4 | [squizlabs/php_codesniffer](https://packagist.org/packages/squizlabs/php_codesniffer) | 292 | 9.6% |
| 5 | [friendsofphp/php-cs-fixer](https://packagist.org/packages/friendsofphp/php-cs-fixer) | 225 | 7.4% |
| 6 | [mockery/mockery](https://packagist.org/packages/mockery/mockery) | 206 | 6.7% |
| 7 | [rector/rector](https://packagist.org/packages/rector/rector) | 103 | 3.4% |
| 8 | [symfony/var-dumper](https://packagist.org/packages/symfony/var-dumper) | 99 | 3.2% |
| 9 | [mikey179/vfsstream](https://packagist.org/packages/mikey179/vfsstream) | 97 | 3.2% |
| 10 | [fakerphp/faker](https://packagist.org/packages/fakerphp/faker) | 97 | 3.2% |
| 11 | [laravel/pint](https://packagist.org/packages/laravel/pint) | 85 | 2.8% |
| 12 | [phpstan/extension-installer](https://packagist.org/packages/phpstan/extension-installer) | 84 | 2.8% |
| 13 | [nunomaduro/collision](https://packagist.org/packages/nunomaduro/collision) | 82 | 2.7% |
| 14 | [pestphp/pest](https://packagist.org/packages/pestphp/pest) | 82 | 2.7% |
| 15 | [phpstan/phpstan-phpunit](https://packagist.org/packages/phpstan/phpstan-phpunit) | 82 | 2.7% |
| 16 | [vimeo/psalm](https://packagist.org/packages/vimeo/psalm) | 78 | 2.6% |
| 17 | [roave/security-advisories](https://packagist.org/packages/roave/security-advisories) | 71 | 2.3% |
| 18 | [symfony/phpunit-bridge](https://packagist.org/packages/symfony/phpunit-bridge) | 64 | 2.1% |
| 19 | [phpstan/phpstan-strict-rules](https://packagist.org/packages/phpstan/phpstan-strict-rules) | 57 | 1.9% |
| 20 | [phpstan/phpstan-deprecation-rules](https://packagist.org/packages/phpstan/phpstan-deprecation-rules) | 53 | 1.7% |
| 21 | [symfony/process](https://packagist.org/packages/symfony/process) | 51 | 1.7% |
| 22 | [phpmd/phpmd](https://packagist.org/packages/phpmd/phpmd) | 51 | 1.7% |
| 23 | [orchestra/testbench](https://packagist.org/packages/orchestra/testbench) | 49 | 1.6% |
| 24 | [symfony/browser-kit](https://packagist.org/packages/symfony/browser-kit) | 48 | 1.6% |
| 25 | [phpspec/prophecy-phpunit](https://packagist.org/packages/phpspec/prophecy-phpunit) | 43 | 1.4% |
| 26 | [infection/infection](https://packagist.org/packages/infection/infection) | 40 | 1.3% |
| 27 | [symfony/css-selector](https://packagist.org/packages/symfony/css-selector) | 39 | 1.3% |
| 28 | [php-coveralls/php-coveralls](https://packagist.org/packages/php-coveralls/php-coveralls) | 37 | 1.2% |
| 29 | [symfony/console](https://packagist.org/packages/symfony/console) | 36 | 1.2% |
| 30 | [laravel/sail](https://packagist.org/packages/laravel/sail) | 36 | 1.2% |
| 31 | [php-parallel-lint/php-parallel-lint](https://packagist.org/packages/php-parallel-lint/php-parallel-lint) | 36 | 1.2% |
| 32 | [ergebnis/composer-normalize](https://packagist.org/packages/ergebnis/composer-normalize) | 35 | 1.1% |
| 33 | [symfony/web-profiler-bundle](https://packagist.org/packages/symfony/web-profiler-bundle) | 33 | 1.1% |
| 34 | [phpcompatibility/php-compatibility](https://packagist.org/packages/phpcompatibility/php-compatibility) | 33 | 1.1% |
| 35 | [phpbench/phpbench](https://packagist.org/packages/phpbench/phpbench) | 32 | 1.0% |
| 36 | [phpspec/phpspec](https://packagist.org/packages/phpspec/phpspec) | 31 | 1.0% |
| 37 | [symfony/yaml](https://packagist.org/packages/symfony/yaml) | 30 | 1.0% |
| 38 | [dealerdirect/phpcodesniffer-composer-installer](https://packagist.org/packages/dealerdirect/phpcodesniffer-composer-installer) | 30 | 1.0% |
| 39 | [spatie/laravel-ignition](https://packagist.org/packages/spatie/laravel-ignition) | 30 | 1.0% |
| 40 | [bamarni/composer-bin-plugin](https://packagist.org/packages/bamarni/composer-bin-plugin) | 29 | 1.0% |
| 41 | [symfony/filesystem](https://packagist.org/packages/symfony/filesystem) | 27 | 0.9% |
| 42 | [larastan/larastan](https://packagist.org/packages/larastan/larastan) | 27 | 0.9% |
| 43 | [symfony/debug-bundle](https://packagist.org/packages/symfony/debug-bundle) | 27 | 0.9% |
| 44 | [satooshi/php-coveralls](https://packagist.org/packages/satooshi/php-coveralls) | 26 | 0.9% |
| 45 | [symfony/stopwatch](https://packagist.org/packages/symfony/stopwatch) | 25 | 0.8% |
| 46 | [pestphp/pest-plugin-laravel](https://packagist.org/packages/pestphp/pest-plugin-laravel) | 25 | 0.8% |
| 47 | [symfony/dom-crawler](https://packagist.org/packages/symfony/dom-crawler) | 25 | 0.8% |
| 48 | [guzzlehttp/guzzle](https://packagist.org/packages/guzzlehttp/guzzle) | 25 | 0.8% |
| 49 | [phpstan/phpstan-symfony](https://packagist.org/packages/phpstan/phpstan-symfony) | 24 | 0.8% |
| 50 | [behat/behat](https://packagist.org/packages/behat/behat) | 23 | 0.8% |

A third of the corpus tests with PHPUnit. Just over a quarter requires `composer/composer` itself in dev: this is expected, since a Composer plugin needs the Composer API to type-hint against and to run its test suite against real plugin activation. PHPStan alone, at 12.2%, is already well ahead of Psalm, at 2.6%, and counting the whole family together, `phpstan/phpstan` plus its satellites `extension-installer`, `phpunit`, `strict-rules`, `deprecation-rules`, `symfony`, 390 projects, or 12.8% of the corpus, use at least one of them. Pest is present, 2.7% but PHPUnit is still the default by an order of magnitude.

## Requested versions vs. what's actually on Packagist today

This is the part I find the most telling. For each of the most-required packages, I looked at every version constraint written across the corpus, broke `||`-separated ranges into individual major versions, and compared the most commonly *targeted* major against the current stable release on Packagist.

| Package | Latest on Packagist | Most-required major | Projects compatible with the latest major |
| ------- | ------------------- | ------------------- | ----------------------------------------- |
| [symfony/console](https://packagist.org/packages/symfony/console) | [8.1.5](https://packagist.org/packages/symfony/console#8.1.5) | v6 (44% of projects) | 20% |
| [symfony/yaml](https://packagist.org/packages/symfony/yaml) | [8.1.5](https://packagist.org/packages/symfony/yaml#8.1.5) | v7 (35% of projects) | 9% |
| [guzzlehttp/guzzle](https://packagist.org/packages/guzzlehttp/guzzle) | [8.1.0](https://packagist.org/packages/guzzlehttp/guzzle#8.1.0) | v7 (83% of projects) | 2% |
| [psr/log](https://packagist.org/packages/psr/log) | [3.0.2](https://packagist.org/packages/psr/log#3.0.2) | v3 (70% of projects) | 70% |
| [symfony/filesystem](https://packagist.org/packages/symfony/filesystem) | [8.1.5](https://packagist.org/packages/symfony/filesystem#8.1.5) | v6 (47% of projects) | 12% |
| [symfony/finder](https://packagist.org/packages/symfony/finder) | [8.1.5](https://packagist.org/packages/symfony/finder#8.1.5) | v6 (42% of projects) | 18% |
| [symfony/process](https://packagist.org/packages/symfony/process) | [8.1.5](https://packagist.org/packages/symfony/process#8.1.5) | v7 (45% of projects) | 23% |
| [laravel/framework](https://packagist.org/packages/laravel/framework) | [13.29.0](https://packagist.org/packages/laravel/framework#v13.29.0) | v12 (32% of projects) | 24% |
| [twig/twig](https://packagist.org/packages/twig/twig) | [3.28.0](https://packagist.org/packages/twig/twig#v3.28.0) | v3 (78% of projects) | 78% |
| [monolog/monolog](https://packagist.org/packages/monolog/monolog) | [3.10.0](https://packagist.org/packages/monolog/monolog#3.10.0) | v3 (55% of projects) | 55% |
| [composer/installers](https://packagist.org/packages/composer/installers) | [2.3.0](https://packagist.org/packages/composer/installers#v2.3.0) | v1 (82% of projects) | 29% |
| [composer/composer](https://packagist.org/packages/composer/composer) | [2.10.2](https://packagist.org/packages/composer/composer#2.10.2) | v2 (68% of projects) | 68% |
| [doctrine/dbal](https://packagist.org/packages/doctrine/dbal) | [4.4.4](https://packagist.org/packages/doctrine/dbal#4.4.4) | v3 (39% of projects) | 31% |
| [symfony/event-dispatcher](https://packagist.org/packages/symfony/event-dispatcher) | [8.1.5](https://packagist.org/packages/symfony/event-dispatcher#8.1.5) | v6 (41% of projects) | 18% |
| [laravel/tinker](https://packagist.org/packages/laravel/tinker) | [3.0.2](https://packagist.org/packages/laravel/tinker#v3.0.2) | v2 (66% of projects) | 24% |
| [psr/container](https://packagist.org/packages/psr/container) | [2.0.2](https://packagist.org/packages/psr/container#2.0.2) | v1 (78% of projects) | 71% |
| [psr/http-message](https://packagist.org/packages/psr/http-message) | [2.0](https://packagist.org/packages/psr/http-message#2.0.0) | v1 (77% of projects) | 67% |
| [nikic/php-parser](https://packagist.org/packages/nikic/php-parser) | [5.8.0](https://packagist.org/packages/nikic/php-parser#v5.8.0) | v5 (56% of projects) | 56% |
| [vlucas/phpdotenv](https://packagist.org/packages/vlucas/phpdotenv) | [5.7.0](https://packagist.org/packages/vlucas/phpdotenv#v5.7.0) | v5 (58% of projects) | 58% |

A few things jump out:

- **Guzzle is the most striking laggard — though partly excusable.** 83% of the corpus is still pinned to `^7.x`, and only 2% of projects declare a constraint that would accept Guzzle 8. In fairness, [Guzzle 8.0.0 only shipped on 2026-07-20](https://packagist.org/packages/guzzlehttp/guzzle#8.0.0), barely a month before this scan: this is less "ecosystem laggard" and more "the ink isn't dry yet." Worth re-running this query in six months.
- **The Symfony components are all in the same boat.** Console, Yaml, Filesystem, Finder, Process, EventDispatcher: every one of them peaks around major 6 or 7, while Symfony itself is already shipping 8.x. Given Symfony's yearly major-version cadence, this isn't really about laziness; a `^6.0` constraint from a couple of years ago is simply not the kind of thing a plugin maintainer revisits unless something forces their hand.
- **composer/installers v1 → v2 is a genuinely stalled migration, and this one has no excuse.**82% of projects are still on the `^1.0` line: [v2.0.0 shipped back in August 2021](https://packagist.org/packages/composer/installers#v2.0.0). Five years on, four out of five plugins in this corpus still haven't made the jump. If you maintain a Composer plugin, this is probably worth a five-minute check.
- **PSR interfaces show the opposite pattern.** `psr/log`, `psr/container`, `psr/http-message` all sit around 67–71% latest-major compatibility: no surprise, since these interfaces barely change and a wide `^1.0 || ^2.0 || ^3.0` constraint costs nothing to write.
- **Twig and nikic/php-parser are the well-behaved ones** — the most-required major *is* the current major, with 56–78% of projects already on the latest line.

## Type: what kind of package is this, really

`type` is optional, and it shows:

| Type | Projects | Share |
| ---- | -------- | ----- |
| composer-plugin | 1293 | 42.4% |
| *(not set)* | 1074 | 35.2% |
| library | 320 | 10.5% |
| project | 257 | 8.4% |
| symfony-bundle | 13 | 0.4% |
| wordpress-plugin | 13 | 0.4% |
| application | 12 | 0.4% |
| cakephp-plugin | 7 | 0.2% |
| package | 5 | 0.2% |
| neos-package | 5 | 0.2% |
| drupal-module | 5 | 0.2% |
| magento2-module | 4 | 0.1% |
| framework | 4 | 0.1% |
| *29 more types, each with 1–3 occurrences* | 39 | 1.3% |

More than a third of the corpus leaves `type` unset entirely. The default for Composer is to treat it as a `library`, so the *effective* library share is closer to 45%. The long tail of one-off types, such as `kirby-cms`, `s9y-core`, `midcom-package`, `october-plugin`... is a nice reminder of how many CMS-specific plugin ecosystems still route through Composer's `type` field for their custom installers.

## Minimum stability: how much risk are people willing to take

| minimum-stability | Projects | Share |
| ----------------- | -------- | ----- |
| *(not set — defaults to `stable`)* | 1521 | 49.8% |
| dev | 1296 | 42.5% |
| stable | 211 | 6.9% |
| alpha | 12 | 0.4% |
| beta | 8 | 0.3% |
| RC | 4 | 0.1% |

This is the one that surprised me most. `minimum-stability: dev` sits at 42.5%: nearly as high as everyone who left the field alone. That's a huge chunk of the ecosystem explicitly opting in to unreleased, unstable dependency versions by default. It is almost always paired with a `prefer-stable: true` to soften the blow, though I didn't check that here. Composer plugins skew younger and more experimental than the average PHP library, and it shows: this is not a community that's shy about tracking `dev-main`.

And I don't think that's a problem by itself. A component can reasonably stay on `dev` for as long as it has no real users yet. The moment someone actually depends on it in production is the moment they need a version number to freeze, and not a day before. What's healthy here is the appetite: a PHP ecosystem willing to try new ideas before they're polished is a good sign, not a red flag. The gap I keep running into in this data isn't the experimentation itself, it's that nothing beyond a handful of leaders, like Symfony, PHPUnit, PHPStan, etc. gets validated by adoption at any scale. Past the top of each list, popularity falls off a cliff, and there's no real tooling to help a maintainer discover which of the thousands of one-off dependencies in that long tail are actually worth building on. Now that AI makes it trivial to spin up ten experiments where you used to write one, that discovery problem only gets bigger. The bottleneck stops being "can I build this" and becomes "how would anyone downstream ever find out it's good".

---

*Corpus: 3052 valid `composer.json` files scanned across 3285 project directories. Version comparisons pulled live from [Packagist](https://packagist.org/) at the time of writing: check the linked package pages for current numbers, since this particular table will age fast, by design.*