Composer resolves dependencies, which needs memory and network access - both of which are limited on shared hosting. It also downloads code straight onto a production server, which is not where you want to discover that a package has changed.

The better shape

Resolve dependencies where you have the resources, and ship the result. The server then never runs Composer at all.

# on your machine or in CI\ncomposer install --no-dev --optimize-autoloader --classmap-authoritative\nrsync -az --delete vendor/ user@server:/var/www/site/vendor/
  • --no-dev - test frameworks and debuggers are not on production.
  • --optimize-autoloader - a class map instead of filesystem lookups, and a measurable speed-up.
  • --classmap-authoritative - no fallback stat calls at all. Use it only when nothing generates classes at runtime.

If you must run it on the server

php -d memory_limit=-1 /usr/local/bin/composer install --no-dev --optimize-autoloader

The memory limit is the usual blocker. Raising it just for that command avoids raising it for the whole site.

Commit the lock file, never the vendor directory

composer.lock belongs in git - it is what makes two installs identical. The vendor directory does not: it makes the repository enormous and merges impossible.

Deploy without a broken window

Copying files into a live directory means some requests see half of the new code. Build into a new directory and switch a symlink, so the change is atomic.

ln -sfn /var/www/releases/2026-09-05 /var/www/current\nsudo systemctl reload php8.3-fpm       # clear the opcache of the old paths
Reload PHP-FPM after a deploy or opcache will keep serving the previous code from memory - see what opcache caches.