Skip to content

Fix: Composer Allowed Memory Size Exhausted – PHP Fatal Error

FixDevs ·

Quick Answer

How to fix the PHP Composer error 'Allowed memory size exhausted' by increasing memory limits, optimizing dependencies, or using memory_limit flags.

The Error

You run composer update, composer install, or composer require and the process crashes with a fatal error:

PHP Fatal error:  Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes)
in phar:///usr/local/bin/composer/src/Composer/DependencyResolver/Solver.php on line 223

Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes)
in phar:///usr/local/bin/composer/src/Composer/DependencyResolver/Solver.php on line 223

Or a variation with a different byte limit:

PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 67108864 bytes)
in phar:///usr/local/bin/composer/src/Composer/JsonFile.php on line 279

Sometimes the error appears during composer create-project:

Creating a "laravel/laravel" project at "./my-app"
Installing laravel/laravel (v11.0.0)
  - Downloading laravel/laravel (v11.0.0)
  - Installing laravel/laravel (v11.0.0): Extracting archive

PHP Fatal error:  Allowed memory size of 268435456 bytes exhausted (tried to allocate 32768 bytes)
in phar:///usr/local/bin/composer/src/Composer/DependencyResolver/RuleSetGenerator.php on line 53

PHP has a hard ceiling on how much memory a single script can use, and Composer’s dependency resolver has exceeded it. Composer needs to build a dependency graph, evaluate version constraints, resolve conflicts, and download metadata for every package in the tree, all of which consumes significant memory for projects with large dependency trees.

Why This Happens

PHP enforces a per-script memory limit controlled by the memory_limit directive in php.ini. The default value varies by distribution and PHP version, but common defaults are 128 MB, 256 MB, or 512 MB. When Composer runs, it operates as a PHP script and is subject to this limit.

Composer’s dependency resolver is the primary memory consumer. It loads the complete version list and constraint metadata for every package in your dependency tree (including transitive dependencies) into memory to solve the dependency graph. A typical Laravel or Symfony project can have 100 to 300 packages when you count all transitive dependencies. Each package has multiple versions, and each version has its own constraint set. The resolver must evaluate all of them to find a compatible set.

Several factors increase memory consumption beyond the baseline:

Large dependency trees. Projects with many direct dependencies pull in dozens of transitive dependencies. Each additional package multiplies the constraint combinations the resolver must evaluate. A project with 50 direct dependencies might have 250 total packages, and the resolver’s memory usage grows non-linearly with the number of packages and version constraints.

Using composer update instead of composer install. The update command re-resolves the entire dependency tree from scratch, evaluating all available versions of every package. The install command reads composer.lock and installs the exact versions listed there, skipping the resolution step entirely. This is why update often triggers the memory error while install works fine.

Requiring dev dependencies in production. Dev dependencies like PHPUnit, PHPStan, Laravel Dusk, and Faker add packages that are only needed during development. Including them during production deploys doubles the number of packages the resolver must consider.

Outdated Composer versions. Older versions of Composer (especially 1.x) had a less efficient dependency resolver that used significantly more memory. Composer 2.x rewrote the resolver and reduced memory usage dramatically, but even Composer 2 can hit limits on very large projects.

Running inside memory-constrained environments. CI/CD pipelines, Docker containers, shared hosting, and small VPS instances often have both PHP memory limits and system-level memory constraints. A server with 512 MB of RAM running PHP with a 128 MB limit will hit the PHP limit first, but even raising PHP’s limit won’t help if the system itself doesn’t have enough RAM. This is similar to how Java applications can run out of heap space when the JVM allocation exceeds available system memory.

Fix 1: Set the COMPOSER_MEMORY_LIMIT Environment Variable

Composer respects its own COMPOSER_MEMORY_LIMIT environment variable, which overrides PHP’s memory_limit for Composer processes only. Setting it to -1 removes the limit entirely:

COMPOSER_MEMORY_LIMIT=-1 composer update

This is the fastest fix and does not affect any other PHP scripts on the system. The environment variable only applies to the Composer process spawned by that command.

To make it persistent for your shell session:

export COMPOSER_MEMORY_LIMIT=-1
composer update
composer require some/package

To make it permanent across reboots, add it to your shell profile:

# Add to ~/.bashrc, ~/.zshrc, or ~/.profile
echo 'export COMPOSER_MEMORY_LIMIT=-1' >> ~/.bashrc
source ~/.bashrc

On Windows (PowerShell):

$env:COMPOSER_MEMORY_LIMIT = -1
composer update

Or set it permanently via System Environment Variables in Windows Settings.

You can also set a specific value instead of -1 if you want to allow more memory without removing the limit entirely:

COMPOSER_MEMORY_LIMIT=2G composer update

Pro Tip: Use COMPOSER_MEMORY_LIMIT=-1 instead of modifying php.ini. It only affects the Composer process, leaves your web server’s PHP memory limit untouched, and works without requiring root access to edit system config files.

Fix 2: Use the php -d memory_limit Flag

If COMPOSER_MEMORY_LIMIT does not work (some older Composer versions or wrapper scripts may not respect it), you can pass the memory limit directly to the PHP runtime:

php -d memory_limit=-1 $(which composer) update

This tells PHP itself to run with no memory limit for this specific invocation. The $(which composer) part resolves the full path to the Composer binary. If Composer is installed as a .phar file, point to it directly:

php -d memory_limit=-1 /usr/local/bin/composer update

Or if you have Composer as a local file:

php -d memory_limit=-1 composer.phar install

On Windows, find the path to Composer and run:

php -d memory_limit=-1 C:/ProgramData/ComposerSetup/bin/composer.phar update

This approach bypasses both PHP’s php.ini setting and Composer’s own COMPOSER_MEMORY_LIMIT. It is the most reliable way to force unlimited memory for a single command.

Fix 3: Increase memory_limit in php.ini

If you want to permanently raise the memory limit for all PHP CLI scripts (not just Composer), edit the php.ini file used by the CLI version of PHP.

Find the correct php.ini file:

php --ini

This outputs something like:

Configuration File (php.ini) Path: /etc/php/8.3/cli
Loaded Configuration File:         /etc/php/8.3/cli/php.ini
Scan for additional .ini files in: /etc/php/8.3/cli/conf.d

Note that PHP often has separate php.ini files for CLI and the web server (Apache/FPM). You need the CLI version since Composer runs from the command line.

Edit the php.ini file:

sudo nano /etc/php/8.3/cli/php.ini

Find the memory_limit directive and increase it:

; Before
memory_limit = 128M

; After - set to 2 GB or unlimited
memory_limit = 2G
; Or remove the limit entirely:
; memory_limit = -1

Save and verify:

php -i | grep memory_limit

Setting memory_limit = -1 in php.ini removes the limit permanently for all CLI scripts. This is generally safe for development machines but should be used with caution on production servers where a runaway script could consume all available memory.

Fix 4: Use composer install Instead of composer update

If you already have a composer.lock file and only need to install the locked dependencies, always use install instead of update:

# This resolves the entire dependency tree (uses lots of memory)
composer update

# This reads composer.lock and installs exact versions (uses much less memory)
composer install

The composer install command skips the dependency resolution step entirely. It reads the pinned versions from composer.lock and downloads them directly. This uses a fraction of the memory that update requires because there is no solver involved.

Use composer update only when you intentionally want to update dependencies to newer versions. For CI/CD pipelines and production deploys, composer install should always be the command you use. If your environment variables are not loading correctly in CI, see Fix: Environment Variable Undefined for troubleshooting that separately.

If you need to update a single package without re-resolving the entire tree:

# Update only one package (much less memory than a full update)
composer update vendor/package-name

This limits the resolver to only the specified package and its dependencies, dramatically reducing memory usage.

Common Mistake: Running composer update on a production server when you should be running composer install. The update command re-resolves the entire dependency tree from scratch (using massive amounts of memory), while install just reads the lockfile and downloads exact versions. Always use install in production and CI.

Fix 5: Use the —no-dev Flag

Dev dependencies can account for a large portion of your dependency tree. If you are building for production or running into memory limits, exclude them:

composer install --no-dev

Or during an update:

composer update --no-dev

This tells Composer to ignore everything listed under require-dev in your composer.json. For a typical Laravel project, this can remove 30 to 50 packages from the resolution tree, significantly reducing memory usage.

In your composer.json, dev dependencies look like this:

{
    "require": {
        "php": "^8.2",
        "laravel/framework": "^11.0",
        "guzzlehttp/guzzle": "^7.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^11.0",
        "laravel/pint": "^1.0",
        "fakerphp/faker": "^1.23",
        "mockery/mockery": "^1.6",
        "nunomaduro/collision": "^8.0",
        "larastan/larastan": "^2.0"
    }
}

Everything under require-dev is skipped with --no-dev. For production deployments, this is also a security and performance best practice since you should never ship testing tools and debug utilities to production.

Fix 6: Optimize the Autoloader

Composer’s autoloader optimization reduces runtime overhead but also affects the memory Composer uses during the dump-autoload phase. Use the optimized autoloader flags to generate a classmap:

composer install --optimize-autoloader --no-dev

Or configure it permanently in composer.json:

{
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true
    }
}

The preferred-install: dist setting tells Composer to download distribution archives (zip files) instead of cloning Git repositories. This uses less memory and disk space because Composer does not need to keep the entire Git history in memory.

You can also combine it with the authoritative classmap option for production:

{
    "config": {
        "optimize-autoloader": true,
        "classmap-authoritative": true
    }
}

The classmap-authoritative flag tells the autoloader not to fall back to PSR-4 directory scanning if a class is not found in the classmap. This is faster at runtime and eliminates file-system lookups, but it means any class not in the map will not be found. Only use this in production where you know all classes are properly mapped.

Fix 7: Configure Platform Requirements

If Composer’s resolver is struggling because it is evaluating packages for PHP extensions or versions you do not have, you can constrain the platform configuration in composer.json:

{
    "config": {
        "platform": {
            "php": "8.2.0",
            "ext-mbstring": "8.2.0",
            "ext-intl": "8.2.0"
        }
    }
}

This tells Composer to resolve dependencies as if you were running PHP 8.2.0 with the specified extensions, regardless of what is actually installed. This can reduce the number of candidate versions the resolver evaluates because it immediately eliminates packages that require a different PHP version.

You can also use platform-check to disable runtime platform checks if you know your deployment target matches:

{
    "config": {
        "platform-check": false
    }
}

Be careful with this setting. If your deployment target has a different PHP version or is missing extensions, you will get runtime errors instead of install-time errors.

To see what Composer detects about your current platform:

composer show --platform

This lists your PHP version, loaded extensions, and system libraries that Composer considers during resolution. If something unexpected appears here, it can cause the resolver to evaluate unnecessary package versions.

Fix 8: Fix Memory Issues in Docker Builds

Docker builds are particularly prone to Composer memory errors because containers often run with limited memory. The dependency resolution step can fail even when the final application would fit in memory easily.

Increase Docker’s memory allocation:

# Dockerfile
FROM php:8.3-cli

# Install system dependencies
RUN apt-get update && apt-get install -y \
    git \
    unzip \
    libzip-dev \
    && docker-php-ext-install zip

# Install Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

# Set memory limit for Composer
ENV COMPOSER_MEMORY_LIMIT=-1

# Copy dependency files first (layer caching)
COPY composer.json composer.lock ./

# Install dependencies
RUN composer install --no-dev --optimize-autoloader --no-scripts --no-interaction

# Copy application code
COPY . .

# Run post-install scripts
RUN composer run-script post-install-cmd --no-interaction || true

Key practices for Docker builds:

  1. Set COMPOSER_MEMORY_LIMIT=-1 as an ENV directive so it applies to all Composer commands in the build.
  2. Copy composer.json and composer.lock before copying the rest of the code. Docker caches layers, so dependencies are only re-resolved when these files change.
  3. Use composer install with --no-dev and --no-scripts. Scripts often depend on application code that hasn’t been copied yet, and dev dependencies are unnecessary in production images.

If your Docker container exits unexpectedly during builds, the host machine might be running out of memory. Check Docker Desktop’s resource settings or the Docker daemon configuration:

# Check Docker's memory allocation
docker info | grep "Total Memory"

# Run the build with increased memory
docker build --memory=4g -t myapp .

For multi-stage builds, run Composer in a separate stage with more resources:

# Stage 1: Install dependencies
FROM composer:latest AS deps
WORKDIR /app
COPY composer.json composer.lock ./
RUN composer install --no-dev --optimize-autoloader --no-scripts --ignore-platform-reqs

# Stage 2: Production image
FROM php:8.3-fpm-alpine
WORKDIR /var/www/html
COPY --from=deps /app/vendor ./vendor
COPY . .

The --ignore-platform-reqs flag in the first stage lets you install dependencies in the Composer image even if it does not have the same PHP extensions as your production image. The platform requirements will be checked at runtime. For more container startup problems, check Fix: Docker Compose Up Errors.

Fix 9: Add Swap Space

On servers with limited RAM, adding swap space provides overflow memory that the OS can use when physical RAM runs out. This is slower than RAM but prevents outright crashes when Composer temporarily needs more memory than is available.

Check current swap:

free -h
swapon --show

Create a swap file (Linux):

# Create a 2 GB swap file
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Verify
free -h

Make it permanent across reboots:

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Swap is especially useful on small VPS instances (1 GB or 2 GB RAM) and CI/CD runners that run Composer as part of deployment pipelines. The dependency resolution will be slower because disk I/O is orders of magnitude slower than RAM, but it will complete instead of crashing.

You can tune how aggressively Linux uses swap with the swappiness parameter:

# Check current swappiness (default is 60)
cat /proc/sys/vm/swappiness

# Reduce to 10 (prefer RAM, use swap only when needed)
sudo sysctl vm.swappiness=10

A lower swappiness value means the system will try harder to keep things in RAM and only spill to swap when memory pressure is high. For a server that primarily runs Composer during deploys, a swappiness of 10 to 20 is reasonable.

Still Not Working?

Update Composer to the latest version

Composer 2.x has dramatically better memory efficiency than Composer 1.x. If you are still on Composer 1, upgrading is the single biggest improvement you can make:

composer self-update

# Or update to a specific major version
composer self-update --2

Check your current version:

composer --version

Composer 2.2+ introduced further optimizations for dependency resolution memory usage. Always use the latest stable version.

Clear Composer’s cache

A corrupted or bloated cache can contribute to memory issues:

# Clear all caches
composer clear-cache

# Check cache directory size
composer config cache-dir
du -sh $(composer config cache-dir)

If the cache directory is several gigabytes, clearing it frees disk space and can resolve issues where Composer loads stale or corrupted package metadata into memory.

Check for circular dependencies

Circular or overly complex dependency constraints can cause the resolver to explore an exponentially large solution space. Run the dependency resolution with verbose output to see where it gets stuck:

COMPOSER_MEMORY_LIMIT=-1 composer update -vvv 2>&1 | tail -100

The triple -vvv flag shows every step of the resolution process. If you see the resolver repeatedly backtracking on the same set of packages, those packages have conflicting constraints. This is conceptually similar to how npm struggles with conflicting peer dependencies — the resolver must explore many combinations before concluding that no solution exists or finding one that satisfies all constraints.

Diagnose specific package issues

If memory exhaustion happens only when adding or updating a specific package, check what that package pulls in:

composer depends vendor/package-name --tree
composer show vendor/package-name --all

The --tree flag shows the full transitive dependency tree. A single package that depends on dozens of other packages can significantly increase the resolver’s memory usage.

Use —prefer-dist and —no-plugins

Reduce Composer’s memory footprint by skipping plugin execution and preferring zip downloads:

composer install --prefer-dist --no-plugins --no-scripts

Plugins run arbitrary PHP code during the install process and can allocate significant memory. If a plugin is causing the memory issue (not the resolver itself), --no-plugins will bypass it.

Profile Composer’s memory usage

Composer can report its own memory usage:

COMPOSER_MEMORY_LIMIT=-1 composer update --profile

The --profile flag adds memory and time information to the output. This tells you exactly how much memory each phase of the install/update uses, helping you identify whether the resolver, the downloader, or a plugin is the main consumer.

Check for pip/npm-like dependency conflicts

If your PHP project integrates with frontend tooling or Python services, memory issues in one package manager can masquerade as issues in another. Make sure you are diagnosing the right tool. For Python dependency issues, see Fix: pip No Matching Distribution Found. For Node.js dependency tree conflicts, see Fix: npm ERESOLVE Unable to Resolve Dependency Tree.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles