What is Composer for Magento?
Short answer
Composer is the PHP dependency manager that installs and upgrades Magento 2. Magento itself is a metapackage (magento/product-community-edition for Open Source, magento/product-enterprise-edition for Adobe Commerce) that you pull from repo.magento.com after adding your Marketplace access keys to auth.json. On every store I work on the flow is the same: composer require brings the code into vendor/, then bin/magento setup:upgrade registers it with Magento. Metapackage upgrades go through magento/composer-root-update-plugin, and many teams add cweagans/composer-patches to apply vendor fixes from patch files.
- Authenticate against repo.magento.com 01
- Install the project, create-project for greenfield, install for clones 02
- Add a third-party module with composer require 03
- Run bin/magento setup:upgrade to wire the module into Magento 04
- Production mode: di:compile, static-content:deploy, cache:flush 05
Most common mistake Committing auth.json, leaking the Marketplace private key
Five steps from auth.json to a deployed module
Composer does four jobs at once: it logs in to a package repo, solves version constraints, downloads code and writes the autoloader. Here is what each step does to a Magento install, in the order I run them.
-
01
Authenticate against repo.magento.com
Log in to
marketplace.magento.com, go to My Profile → Access Keys and create a key pair. The public key is the Composerusernameand the private key is thepassword. I put them inauth.jsonat the project root (gitignored, mode0600) or in~/.composer/auth.jsonon a CI runner. The file looks like{"http-basic":{"repo.magento.com":{"username":"PUBLIC","password":"PRIVATE"}}}. Without it, everycomposer requireagainst the Magento repo returns a 401. -
02
Install the project, create-project for greenfield, install for clones
For a new store:
composer create-project --repository=https://repo.magento.com/ magento/project-community-edition=2.4.7 <dir>. That pulls the metapackage, resolves the tree and lays down the normal Magento folders. For an existing repo I clone, I runcomposer install, notcomposer update. Install reads the committedcomposer.lockand rebuilds the exact samevendor/tree. Update would rewrite the lockfile for every package. The metapackage is only a list; the real code lands invendor/magento/*. -
03
Add a third-party module with composer require
composer require vendor/module-name:^1.2checks the constraint against the package’s owncomposer.json, downloads it tovendor/vendor/module-name/, rebuildsvendor/composer/autoload_*.phpand writes the exact resolved version tocomposer.lock. At this point Magento still doesn’t know the module exists. I always use^or~constraints. A*in production means the next install can pull a major version nobody tested. -
04
Run bin/magento setup:upgrade to wire the module into Magento
setup:upgradereads the module’sregistration.php, adds it toapp/etc/config.php(the enable and disable list) and runs every newSetup/Patch/DataandSetup/Patch/Schemapatch, recording each one in thepatch_listtable. Module versions are tracked insetup_module. Skip this step and the code sits on disk while the database knows nothing about it, so plugins and observers don’t fire and admin menus don’t appear. -
05
Production mode: di:compile, static-content:deploy, cache:flush
In production mode I run three more commands after
setup:upgrade.bin/magento setup:di:compilewrites interceptors, factories and proxies intogenerated/code/.bin/magento setup:static-content:deploy -f en_USrebuildspub/static/for each locale.bin/magento cache:flushclears the cache storage so the new code is served. Miss one and you get the usual report: the change works on dev, production still shows the old behaviour.
Four scenarios where Composer is the only correct answer
On Magento 2, Composer is how you install, upgrade and add extensions. These are the four cases where I most often see teams try to work around it, and where it costs them later.
-
Greenfield Magento install, bootstrap with create-project
For a new store I always start with
composer create-projectagainstrepo.magento.com, never a copy of someone else’s working tree. You get the standard folder layout, a rootcomposer.jsonpinned to the Magento version you asked for, and a freshcomposer.lock. A copied tree brings its oldvendor/, its lockfile drift and any local patches nobody committed. -
Adding a Marketplace or third-party extension
Use
composer require vendor/module:^x.yinstead of unzipping intoapp/code/. Composer modules live invendor/, autoload through PSR-4 and are pinned incomposer.lock, so every developer, CI runner and server gets the same code. A zip inapp/code/skips dependency checks. You find the clashingguzzlehttp/guzzleversion at runtime, and the module rarely gets updated because nobody remembers which version it is. -
Upgrading Magento itself (2.4.x → 2.4.y)
Patch and minor upgrades run through Composer:
composer require magento/product-community-edition=2.4.7 --no-update, thencomposer update. Themagento/composer-root-update-plugincompares your rootcomposer.jsonwith the new metapackage and merges in added, removed and changed requirements, while keeping your ownrequireentries. Before any upgrade I check that the plugin is installed. -
CI / CD pipelines, install --no-dev --optimize-autoloader
Every staging or production build in CI should run
composer install --no-dev --optimize-autoloader --no-interaction.--no-devleaves out PHPUnit, MFTF, phpstan and the other dev tools.--optimize-autoloaderbuilds a classmap so PHP doesn’t search the filesystem on each class load.--no-interactionstops the build from hanging on a prompt whenauth.jsonis missing on a fresh runner.
Three Composer mistakes that wreck Magento deployments
Every emergency Composer call I get from a Magento team comes down to one of these three. Audit your repo and your deploy script before the next release.
-
Committing auth.json, leaking the Marketplace private key
The single most common Magento Composer mistake: developers add
auth.jsonto git "just for this one commit" and forget to remove it. The private key is now in the git history forever, even if yougit rmthe file later, anyone with repo access cangit log -p auth.jsonand pull the credentials. Always.gitignoreauth.jsonfrom day one, load credentials via environment variables (COMPOSER_AUTH) or CI secrets in pipelines (GitHub Actions / GitLab CI), and rotate the Marketplace keys immediately if you ever do leak them via the My Profile → Access Keys screen. -
Running composer update in production instead of composer require
In production,
composer updateis almost always wrong.updaterecalculates every package in the tree against the constraints incomposer.jsonand rewritescomposer.lock, meaning a one-line "bump module X to 1.3" turns into a 200-line lockfile diff that touches Magento core, every third-party module, and every transitive dependency. The safe pattern:composer require vendor/pkg:^1.3 --update-with-dependencies, this updates only the named package and its dependency closure, leaving the rest of the lockfile alone. Usecomposer updateonly on a dedicated upgrade branch where you can review the whole diff. -
Forgetting --no-dev --optimize-autoloader on production
Run
composer installwithout flags on a production box and you get the dev dependencies (PHPUnit, MFTF, phpstan, php-cs-fixer, ~150MB of test framework) and the slower unoptimised autoloader that walks the filesystem on every class load. The dev tooling alone isn’t a security risk per se, but it bloats the deploy artefact, slows up rsync, and the unoptimised autoloader costs a measurable 3-8% on TTFB at scale. The fix is one flag pair:--no-dev --optimize-autoloader, should be in every deploy script and every DockerfileRUN composer installstep.
Composer for Magento, frequently asked questions
-
Composer vs git for Magento, when do I use which?
Use Composer for everything that can be a dependency, Magento core, third-party Marketplace modules, vendor libraries, and any module published to Packagist or a private Composer repo. Use git for your project root (thecomposer.json,composer.lock,app/code/custom modules,app/design/themes,app/etc/config.php, and configuration) but never forvendor/itself,vendor/belongs in.gitignoreand is rebuilt bycomposer installon every deploy. The one exception: tiny project-specific theme tweaks or fixes you haven’t had time to package can live underapp/code/as git-tracked code. Anything you’d reuse across projects should be a real Composer package. -
Why is composer require so slow on Magento, and how do I speed it up?
Magento’s dependency tree is enormous, roughly 200+ packages on a vanilla install, andrepo.magento.comcan be slow to respond to the metadata API, especially during release windows. Speed-ups: (1) commitcomposer.lockand usecomposer installin CI rather thancomposer require,installreads the lockfile and skips constraint resolution; (2) use--prefer-distto pull zipped releases instead ofgit cloneing every package; (3) runcomposer install --no-devon production to drop ~30+ dev-only packages; (4) on Composer 1.x, install the now-archivedhirak/prestissimoparallel downloader, on Composer 2.x parallel downloads are built-in and prestissimo is no longer needed. (5) Cache the~/.composer/cachedirectory in CI between builds. -
What is magento/composer-root-update-plugin and do I need it?
Yes, you need it on every Magento install you ever plan to upgrade. The plugin patches Composer’s upgrade behaviour so thatcomposer require magento/product-community-edition=2.4.ydoesn’t silently overwrite your project rootcomposer.json. Without the plugin, upgrading the metapackage clobbers any customrequirelines you added (third-party modules, your own packages, patch declarations) because Composer sees them as conflicts against the new base. The plugin runs a three-way merge between (a) your current project root, (b) the previous metapackage version’s base, and (c) the new metapackage’s base, preserving your additions while applying core changes. It ships in the Magento metapackage from 2.3.3 onward; verify it’s in yourcomposer.jsonrequire-list before doing any version bump. -
How do I apply a vendor patch with cweagans/composer-patches?
Install the plugin:composer require cweagans/composer-patches. Then in your project rootcomposer.json, add anextra.patchesmap keyed by package name with the patch description and file path:"extra":{"patches":{"magento/module-catalog":{"Fix indexer race condition":"patches/MAGECLOUD-1234.patch"}}}. Patches are unified diffs, generate them withgit diff > patches/MAGECLOUD-1234.patchagainst the original vendor file. Commit the patch file to your repo. On the nextcomposer install/composer update, the plugin applies the patch automatically after the package is extracted. The patches re-apply on every install, so you never lose them on a fresh deploy. This is the correct pattern for any one-off vendor fix you can’t wait for upstream to ship. -
Can I install Magento without Composer?
Technically yes, you can git-clone the Magento source and run with a manually-wired autoloader, but you’ll lose Marketplace access (nocomposer requirefor paid extensions), dependency resolution (no automated conflict detection between modules), the optimised classmap autoloader (slower TTFB), and the supported upgrade path (nocomposer-root-update-pluginto handle metapackage diffs). In practice no real production Magento store runs without Composer in 2026, it’s the official, documented, supported install path since Magento 2.0 launched in 2015. The "git-only" install was deprecated almost immediately. If you find documentation that says otherwise it’s pre-2016 and should be ignored. -
Why does Composer ask for repo.magento.com credentials on every command?
Eitherauth.jsonis missing from the project root, the global~/.composer/auth.jsondoesn’t have the credentials, or the file exists but the running user can’t read it (wrong owner / wrong mode). Fixes in order: (1) createauth.jsonin the project root with the Marketplace public + private keys underhttp-basic.repo.magento.com; (2)chmod 600 auth.jsonandchownit to the user running Composer (oftenwww-dataon shared hosts, the developer’s own UID on local); (3) verify by runningcomposer config --global http-basic.repo.magento.com, should print the username / password without prompting. (4) On CI, inject credentials viaCOMPOSER_AUTHenvironment variable as a JSON-encoded string. Never commitauth.jsonto git.
Want a Composer + dependency audit on your Magento store?
Send your storefront URL, I will check your composer.json, lockfile drift, third-party module pinning, auth.json hygiene, root-update-plugin presence, deploy-script flags, and patch-file workflow, then reply with a written tuning plan, fixed-price quote, and earliest start date. 24-business-hour turnaround.