Skip to content
5.0 Upwork, 100+ reviews Adobe Certified since 2021 New: become your own Magento developer Learn more →
Magento glossary

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.

How it works
  1. Authenticate against repo.magento.com 01
  2. Install the project, create-project for greenfield, install for clones 02
  3. Add a third-party module with composer require 03
  4. Run bin/magento setup:upgrade to wire the module into Magento 04
  5. Production mode: di:compile, static-content:deploy, cache:flush 05
Each step is explained below

Most common mistake Committing auth.json, leaking the Marketplace private key

How it works

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.

  1. 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 Composer username and the private key is the password. I put them in auth.json at the project root (gitignored, mode 0600) or in ~/.composer/auth.json on a CI runner. The file looks like {"http-basic":{"repo.magento.com":{"username":"PUBLIC","password":"PRIVATE"}}}. Without it, every composer require against the Magento repo returns a 401.

  2. 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 run composer install, not composer update. Install reads the committed composer.lock and rebuilds the exact same vendor/ tree. Update would rewrite the lockfile for every package. The metapackage is only a list; the real code lands in vendor/magento/*.

  3. 03

    Add a third-party module with composer require

    composer require vendor/module-name:^1.2 checks the constraint against the package’s own composer.json, downloads it to vendor/vendor/module-name/, rebuilds vendor/composer/autoload_*.php and writes the exact resolved version to composer.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.

  4. 04

    Run bin/magento setup:upgrade to wire the module into Magento

    setup:upgrade reads the module’s registration.php, adds it to app/etc/config.php (the enable and disable list) and runs every new Setup/Patch/Data and Setup/Patch/Schema patch, recording each one in the patch_list table. Module versions are tracked in setup_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.

  5. 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:compile writes interceptors, factories and proxies into generated/code/. bin/magento setup:static-content:deploy -f en_US rebuilds pub/static/ for each locale. bin/magento cache:flush clears 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.

When to use

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-project against repo.magento.com, never a copy of someone else’s working tree. You get the standard folder layout, a root composer.json pinned to the Magento version you asked for, and a fresh composer.lock. A copied tree brings its old vendor/, its lockfile drift and any local patches nobody committed.

  • Adding a Marketplace or third-party extension

    Use composer require vendor/module:^x.y instead of unzipping into app/code/. Composer modules live in vendor/, autoload through PSR-4 and are pinned in composer.lock, so every developer, CI runner and server gets the same code. A zip in app/code/ skips dependency checks. You find the clashing guzzlehttp/guzzle version 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, then composer update. The magento/composer-root-update-plugin compares your root composer.json with the new metapackage and merges in added, removed and changed requirements, while keeping your own require entries. 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-dev leaves out PHPUnit, MFTF, phpstan and the other dev tools. --optimize-autoloader builds a classmap so PHP doesn’t search the filesystem on each class load. --no-interaction stops the build from hanging on a prompt when auth.json is missing on a fresh runner.

Common mistakes

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.json to git "just for this one commit" and forget to remove it. The private key is now in the git history forever, even if you git rm the file later, anyone with repo access can git log -p auth.json and pull the credentials. Always .gitignore auth.json from 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 update is almost always wrong. update recalculates every package in the tree against the constraints in composer.json and rewrites composer.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. Use composer update only on a dedicated upgrade branch where you can review the whole diff.

  • Forgetting --no-dev --optimize-autoloader on production

    Run composer install without 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 Dockerfile RUN composer install step.

FAQ

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 (the composer.json, composer.lock, app/code/ custom modules, app/design/ themes, app/etc/config.php, and configuration) but never for vendor/ itself, vendor/ belongs in .gitignore and is rebuilt by composer install on every deploy. The one exception: tiny project-specific theme tweaks or fixes you haven’t had time to package can live under app/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, and repo.magento.com can be slow to respond to the metadata API, especially during release windows. Speed-ups: (1) commit composer.lock and use composer install in CI rather than composer require, install reads the lockfile and skips constraint resolution; (2) use --prefer-dist to pull zipped releases instead of git cloneing every package; (3) run composer install --no-dev on production to drop ~30+ dev-only packages; (4) on Composer 1.x, install the now-archived hirak/prestissimo parallel downloader, on Composer 2.x parallel downloads are built-in and prestissimo is no longer needed. (5) Cache the ~/.composer/cache directory 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 that composer require magento/product-community-edition=2.4.y doesn’t silently overwrite your project root composer.json. Without the plugin, upgrading the metapackage clobbers any custom require lines 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 your composer.json require-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 root composer.json, add an extra.patches map 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 with git diff > patches/MAGECLOUD-1234.patch against the original vendor file. Commit the patch file to your repo. On the next composer 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 (no composer require for paid extensions), dependency resolution (no automated conflict detection between modules), the optimised classmap autoloader (slower TTFB), and the supported upgrade path (no composer-root-update-plugin to 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?
    Either auth.json is missing from the project root, the global ~/.composer/auth.json doesn’t have the credentials, or the file exists but the running user can’t read it (wrong owner / wrong mode). Fixes in order: (1) create auth.json in the project root with the Marketplace public + private keys under http-basic.repo.magento.com; (2) chmod 600 auth.json and chown it to the user running Composer (often www-data on shared hosts, the developer’s own UID on local); (3) verify by running composer config --global http-basic.repo.magento.com, should print the username / password without prompting. (4) On CI, inject credentials via COMPOSER_AUTH environment variable as a JSON-encoded string. Never commit auth.json to git.
Composer audit

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.

Kishan Savaliya Online 10 AM to 7 PM IST Chat on WhatsApp