Top Composer Pitfalls in Drupal Projects: Real-World Fixes from Support Frontlines
This article covers a session presented by Mohammad Zomorodian, Lead Support Engineer at Acquia, at DrupalCon Vienna.
Composer is the backbone of modern PHP and Drupal development, but it comes with its own set of challenges. Drawing from eight years of hands-on experience supporting enterprise Drupal sites at Acquia, I’ve compiled the most common Composer problems I’ve encountered in real-world projects, along with practical solutions. These are not theoretical or AI-generated issues—they’re the actual pain points faced by teams running large-scale Drupal sites.
PHP Version Mismatches
One of the most frequent Composer errors is a PHP version mismatch:
"The package requires PHP version X, but your PHP version does not satisfy that requirement."
This issue can be deceptively tricky because the PHP version must match everywhere: in your 'composer.json' (both 'require' and 'config.platform.php'), on your local machine, in your CI/CD environment (such as GitLab or GitHub Actions), in your YAML CI/CD configuration files, and on your production server.
Solution: Double-check all environments for PHP version consistency, explicitly set the PHP version in 'composer.json', and ensure your CI/CD YAML files specify the correct PHP version.
Misuse of 'require' vs. 'require-dev'
Mixing up 'require' and 'require-dev' leads to unnecessary packages in production, security risks, and slow deployments.
Best Practices: Use 'require' for packages needed in production and 'require-dev' for development-only tools (like PHPUnit or Drush). Deploy with 'composer install --no-dev' to exclude dev dependencies. This keeps your production environment secure and your deployments fast.
Direct Installation of Symfony Packages
Manually installing Symfony packages to resolve conflicts is a common but dangerous workaround. For example, installing 'symfony/console' v5.4 when Drupal 10.1 requires v6.0 creates version conflicts and breaks your site.
Solution: Avoid installing Symfony packages directly unless absolutely necessary for custom work. Let Drupal and Composer manage Symfony dependencies.
Vendor Directory Management
Mismanaging the 'vendor' directory can lead to security vulnerabilities and hard-to-debug errors.
Best Practices: Never manually edit the 'vendor' directory. Place it outside the web root (e.g., above 'web/' or 'docroot/'). Use 'drupal/core-vendor-hardening' to remove sensitive files if 'vendor' must be in the web root. Use artifact-based deployments: build your code and dependencies, then deploy the artifact.
Real-World Example: A customer had two 'vendor' directories—one in the root, one above the web root—causing mysterious PHP errors. Deleting the extra directory resolved the issue instantly.
The Hidden Vendor Trap: Git and CI/CD
Committing the 'vendor' directory to Git, then switching to CI/CD-based Composer installs, can leave behind outdated or partial vendor files. This results in autoloading errors and missing classes after deployment.
Solution: Never commit 'vendor' to Git. Add 'vendor/' to '.gitignore'. If you previously committed it, clear the Git cache, remove 'vendor/', and recommit. Always build a fresh 'vendor' directory via Composer in CI/CD.
Composer on Windows vs. Linux/Mac
Composer is cross-platform, but most Drupal projects run on Linux. Windows introduces unique issues: line ending differences, slow performance, case sensitivity problems, path separator issues ('\' vs '/'), and limited symlink support.
Advice: Prefer Linux (native or via VM/WSL) for Drupal development. If you must use Windows, use containers or a Linux VM for consistency.
Symlink Issues on Windows
Composer creates symlinks in 'vendor/bin' for executables. Windows often fails to create these, or Git converts them to text files, causing errors like "unable to create symlink" or "filename too long".
Solution: Use Linux or WSL for development. If on Windows, use a VM or containerized environment.
Direct Module Installation and Dependency Conflicts
Directly requiring both a module and its dependencies (e.g., 'composer require drupal/pathauto drupal/token') can cause version conflicts if you specify incompatible versions.
Best Practice: Only require the main module (e.g., 'drupal/pathauto'). Let Composer resolve and install dependencies automatically.
Locking Dependency Versions
Hardcoding exact versions (e.g., "drupal/core": "10.1.0") in 'composer.json' blocks updates and security patches, and causes conflicts.
Solution: Use version constraints with caret ('^') or tilde ('~'), e.g., '"drupal/core": "^10.1"'. Let Composer manage minor and patch updates for you.
Additional Helpful Tips
- Regularly run '
composer self-update' to keep Composer itself up to date. - Use '
composer audit' to check for security issues in your dependencies. - Use '
composer why' and 'composer why-not' to diagnose dependency conflicts. - Run '
composer outdated' regularly to keep your project’s dependencies current and secure.
Conclusion
Composer is a powerful tool, but it requires careful management—especially in complex Drupal projects. By following these best practices and learning from real-world issues, you can avoid common pitfalls, keep your deployments smooth, and maintain a secure, reliable Drupal site. Stay proactive, keep your dependencies tidy, and let Composer do the heavy lifting for you.

