Composer is the dependency manager for PHP. Every modern PHP project uses it, and most developers interact with it daily. But many developers use only require, install, and update, missing features that prevent security issues, reduce build times, and simplify complex dependency graphs.
This guide covers practical Composer usage in 2026, from daily workflows to advanced configuration.
Composer 2.7: what is new
Security auditing
1 | # Check all dependencies for known vulnerabilities |
composer audit queries the Packagist security advisory database and reports any installed packages with known CVEs. This should run in every CI pipeline.
1 | Found 2 security vulnerability advisories affecting 2 packages: |
Platform check improvements
1 | # Verify your PHP version and extensions match composer.json requirements |
This catches the common “works on my machine” problem where production has a different PHP version or is missing an extension.
Faster installs
Composer 2.7 improved parallel downloading and metadata caching. Fresh installs are ~30% faster than Composer 2.4. The --prefer-dist flag (default) downloads zip files instead of cloning git repositories, which is faster for most packages.
Essential daily commands
Installing dependencies
1 | # Install from composer.lock (deterministic, for CI and production) |
Always use composer install (not update) in CI and production. install reads composer.lock and installs exact versions. update resolves new versions, which may differ between environments.
Adding packages
1 | # Add a production dependency |
Updating safely
1 | # Preview what would change |
Removing packages
1 | # Remove a package and update the lock file |
Version constraints explained
1 | { |
| Constraint | Meaning | Allows |
|---|---|---|
^2.0 |
Caret (recommended) | >=2.0.0, <3.0.0 |
^2.1.3 |
Caret with patch | >=2.1.3, <3.0.0 |
~2.1 |
Tilde | >=2.1.0, <3.0.0 |
~2.1.3 |
Tilde with patch | >=2.1.3, <2.2.0 |
2.1.* |
Wildcard | >=2.1.0, <2.2.0 |
Use ^ (caret) by default. It allows minor and patch updates (which should be backward compatible) while preventing major version bumps.
The composer.lock file
composer.lock records the exact version of every installed package, including transitive dependencies. It ensures that every developer and every deployment uses identical versions.
Rules:
- Always commit
composer.lockto version control - Never edit
composer.lockmanually - If
composer.lockconflicts in a merge, delete it and runcomposer update
1 | # Verify lock file is in sync with composer.json |
Autoloading
PSR-4 autoloading
1 | { |
Optimized autoloader
1 | # Generate optimized class map for production |
The optimized autoloader converts PSR-4 rules into a static class map, eliminating filesystem lookups. This is measurably faster on production servers.
Classmap autoloading
For directories that do not follow PSR-4:
1 | { |
Scripts and hooks
1 | { |
1 | # Run a custom script |
Private packages
Private Packagist
For organizations with private packages, Private Packagist provides a hosted solution:
1 | { |
Git repositories
1 | { |
Path repositories (monorepos)
1 | { |
Path repositories create symlinks, allowing you to develop multiple packages in a monorepo while maintaining proper dependency declarations.
Platform configuration
1 | { |
The platform setting tells Composer to resolve dependencies as if you were running a specific PHP version, even if your local version differs. This ensures CI and production compatibility.
Common mistakes
Not committing composer.lock: Without the lock file, composer install behaves like composer update, resolving potentially different versions on each machine.
Using composer update in production: Always use composer install --no-dev in production. update may pull in different versions than what was tested.
Ignoring composer audit: Known vulnerabilities in dependencies are the easiest attack vector. Run audit in CI and fix flagged packages promptly.
Requiring exact versions: "vendor/package": "2.1.3" prevents receiving security patches. Use ^2.1.3 instead to allow patch and minor updates.
FAQ
What is the difference between require and require-dev?
require packages are installed everywhere (dev, CI, production). require-dev packages are only installed when --no-dev is not passed. Put test frameworks, linters, and debug tools in require-dev.
How do I resolve dependency conflicts?
Run composer why-not vendor/package 3.0 to see which packages prevent an upgrade. Then update those blocking packages or use composer require vendor/package:^3.0 --with-all-dependencies.
Should I use composer.phar or the global install?
Either works. The global install (composer command) is more convenient. Including composer.phar in the project ensures everyone uses the same Composer version.
Next steps
Run composer audit and composer check-platform-reqs on your project right now. Fix any flagged vulnerabilities and platform mismatches. Then add both commands to your CI pipeline.
For PHP testing frameworks installed via Composer, the PHPUnit and Pest guide covers testing best practices. The Mago linter guide covers static analysis tools that complement Composer’s security auditing.