Composer is how Magento is installed, extended and upgraded - and the difference between a team that deploys confidently and a team that fears composer update is workflow, not tooling. This is the set of practices we standardise on across agency projects.
The Lockfile Is Sacred
composer.lock pins every dependency to an exact version. The rules that keep teams sane:
- Commit the lockfile. Always. It is what makes “works on my machine” equal “works in production”
composer install(reads the lock) on every environment -composer update(rewrites it) only deliberately, in a branch, with review- Update surgically:
composer update vendor/specific-modulefor one package, not a blanket update that moves 200 packages and buries the one you meant to change - Review lockfile diffs in PRs. A lockfile diff that touches packages nobody mentioned is a question, not a rubber stamp
The Repository Landscape
Magento pulls from multiple repositories: repo.magento.com (Adobe’s, credentials required), Packagist (public), and increasingly private sources. Keep credentials in auth.json outside version control or in environment variables wired in CI - committed Adobe credentials leak access to your licence.
For agency work, Private Packagist (or Satis) earns its keep: private module distribution across client projects, mirrored public packages for build reliability, and one place to revoke access when a project ends.
Patching Core (When You Must)
Sometimes a core bug cannot wait for the next release. The cweagans/composer-patches plugin applies patch files at install time:
"extra": {
"patches": {
"magento/module-sales": {
"Fix invoice email race": "patches/MAGECLOUD-1234-invoice-race.patch"
}
}
}
Discipline that keeps patches safe: one patch per issue, stored in patches/ with a descriptive name, a comment linking the upstream issue, and a removal task in the upgrade checklist. Patches that survive three upgrades unreviewed become unowned risk.
The Project Skeleton
Standard structure for team projects:
composer.jsonwith explicit stability and only real constraints (require what you use, not ranges copied from a tutorial)- Custom modules as path repositories or private packages -
app/codecommitted directly is fine for project-specific code; shared libraries belong in packages - A
Makefileor scripts section wrapping common tasks so new developers run one command, not a wiki page of them
Avoiding Dependency Hell
- Run
composer why-not magento/product-community-edition 2.4.7when an upgrade refuses - it names the blocking package directly - Keep extension count honest: every module is a constraint on every future upgrade. The cheapest dependency is the one you deleted
- CI runs
composer validateand a fullcomposer installfrom scratch - a lockfile that cannot install cleanly is caught in CI, not at deploy
Composer rewards boring discipline: commit the lock, update surgically, patch with paperwork, and let CI prove installability. Do that and dependency management stops being a source of fear and becomes what it should be - plumbing nobody thinks about.