Pinning PHP Versions in Composer: How config.platform Prevents Dependency Drift
Composer's config.platform setting pins PHP and extension versions in composer.json so dependency resolution stays consistent across development, CI, and production.
15 Mar 2026, 06:55 UTC

The "works on my machine" problem for PHP dependencies
Composer normally inspects the PHP version and extensions installed on the machine running the command to decide which package versions are eligible. When one developer runs composer update on PHP 8.2 and another runs it on PHP 8.0, they can produce different composer.lock files—the manifest that records exact package versions. The result is a dependency tree that passes tests locally but fails in CI or production, not because the code changed, but because the resolution environment did.
The fix is to stop letting the host decide. Composer's config.platform setting lets you declare the target PHP and extension versions directly in composer.json, making dependency resolution reproducible across machines.
What config.platform actually does
The platform key under config in composer.json tells Composer to pretend it is running on a specific PHP version and specific extension versions, regardless of the real host. It is a map, not a single string. The most common entry is php, but you can also pin individual extensions using keys like ext-mbstring or ext-json.
Because Composer evaluates these values during dependency resolution, the resulting lock file captures the enforced platform. Anyone who later runs composer install against that lock file gets the same package versions, even if their local PHP differs. This behavior is available in Composer 1.10 and later, including all Composer 2.x releases.
A concrete example
Suppose your production environment runs PHP 8.1, but developers use a mix of 8.0, 8.1, and 8.2 locally. Add the platform override to composer.json:
{
"require": {
"php": "^8.1",
"monolog/monolog": "^3.0"
},
"config": {
"platform": {
"php": "8.1.0"
}
}
}
Run the update from your project root (the directory containing composer.json). You need write permission for composer.json and composer.lock:
composer update
After it finishes, confirm the override is active by listing the effective configuration:
composer config --list
Look for the platform entry in the output. Next, inspect composer.lock to verify that the recorded platform requirements match your pin. If you change config.platform.php later, run composer update again so the lock file is regenerated with the new constraints.
To prove reproducibility, run the same project inside a container that has a different PHP version—say PHP 8.0. Because the platform is pinned to 8.1.0, Composer resolves dependencies as if it were on 8.1. The installed packages should match the lock file rather than being downgraded or upgraded based on the container's actual PHP version.
Trade-offs and where this breaks down
Pinning the platform is not free. The most common mistake is treating it as a substitute for testing. If you pin php to 8.1.0 but your production server actually runs PHP 8.0, Composer will happily install packages that require 8.1 syntax. The lock file will look correct, but the application will crash at runtime. Always run composer check-platform-reqs against the real target environment, or deploy to a staging container that mirrors production, before trusting the lock file.
Extension pinning adds another layer of risk. If you set config.platform.ext-redis to a version that is not installed on the host, Composer may select packages that expect that extension version, but the PHP process will fail when it tries to load the extension. Pin extensions only when a specific package genuinely depends on a known extension behavior.
CI pipelines that test against multiple PHP versions need special handling. A single composer.json cannot simultaneously claim to be PHP 8.0 and 8.2. If your matrix includes versions below the pinned platform, you will need to override the setting per job—either by editing composer.json in a setup step or by using a separate configuration file for the matrix build.
Practical checklist
- Set
config.platform.phpto the oldest PHP version you support in production, not the newest version on your laptop. - Run
composer config --listafter changing the platform to confirm Composer sees the override. - Run
composer check-platform-reqsin the actual target environment (or a matching container) to catch mismatches between the pinned platform and the real runtime. - Regenerate the lock file with
composer updatewhenever you adjust the platform values. - In multi-version CI, override or remove the platform pin for jobs that intentionally test older PHP releases.
Used carefully, config.platform turns Composer from an environment-sensitive resolver into a deterministic build tool. Used carelessly, it hides the very incompatibilities you need to find before deployment.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.