Using Composer to Install Drupal and Manage Dependencies

Last updated on
1 March 2026

This documentation needs work. See "Help improve this page" in the sidebar.

Composer can be used to manage Drupal and all its dependencies, including modules, themes, and libraries.

Drupal version compatibility

  • Modern: 11.x, 10.x
  • Legacy: 9.x, 8.x, 7.x

Prerequisites


1. Downloading Drupal core

Modern Drupal (10, 11, 8.8+)

The recommended template is drupal/recommended-project. This ensures dependencies match the official release and places the web-accessible files in a /web folder.

  • Standard installation: composer create-project drupal/recommended-project my_site_name
    • This is the default starting point for all new projects.
    • It creates a project in the my_site_name directory and automatically executes composer install.
  • Specific version installation (e.g., 9.3.12): composer create-project drupal/recommended-project:9.3.12 my_site_name
    • Use this to match a specific environment or test a previous release.
    • All releases can be found at Releases for Drupal core.
  • Development or pre-release installation (e.g., Drupal 11 alpha/beta): composer create-project drupal/recommended-project:^11@alpha
    • Use this for testing upcoming features or the latest major branch.
    • Setting @alpha as minimum stability allows Composer to pull non-stable releases, such as beta or RC. Use @dev for the absolute latest development release.
  • Modified installation: If you want to modify composer.json properties (like renaming the web root) before the initial download, use the --no-install flag.
    • Example: composer create-project --no-install drupal/recommended-project my_site_name.
  • Non-standard path installation: If you require a directory structure without the /web subdirectory or have advanced requirements, see Appendix: manual project initialization.

Note for Windows Users: If a command fails with a "Could not parse version" error, replace single quotes (') with double quotes (") or remove them entirely (e.g., drupal/recommended-project:^10).

For more information, see recommended-project on Github.

Legacy Drupal (7.x)

Use the community-maintained project template:

composer create-project drupal-composer/drupal-project:7.x-dev -n my_site_name

For more information, see Composer template for Drupal projects on Github.

Docker users

If Composer is not installed locally, run the command via a container:

docker run --rm -i --tty -v $PWD:/app composer create-project drupal/recommended-project my_site_name --ignore-platform-reqs


2. Initial setup & installation

Web root configuration

The my_site_name directory contains files that should be outside of your web root and not accessible by the web server, such as composer.json and the /vendor folder.

  • DocumentRoot: The web root is the my_site_name/web directory. Set your Apache or Nginx configuration to point there.
  • Alternate web root: If you need to rename /web to public_html, modify the web-root (under drupal-scaffold) and installer-paths keys in composer.json. See Customizing installation paths.

Installation methods

  • Standard web interface: Navigate to your site's URL in a browser and follow the setup wizard. You will need database credentials and basic site information.
  • Command line (Drush): 
    1. composer require drush/drush
    2. drush site:install. Without arguments, it installs the standard profile and prompts for database credentials.
      For more information, visit the site install document on the official Drush site.
  • Quick-start demo: To evaluate Drupal with the Umami demo: php ./web/core/scripts/drupal quick-start demo_umami


3. Managing modules and themes

All commands must be executed at the root of your project, where the composer.json file is located, not inside the web or core directories. Using Composer for all modules and themes is critical; mixing manual updates with Composer can cause site failures.

  • Download a module or theme: Composer automatically downloads the project and its required third-party libraries.
    • Run: composer require drupal/PROJECT_NAME
    • Example: composer require drupal/token
    • You can use either the project name or a specific module name within a project (e.g., composer require drupal/features_extra or composer require drupal/fe_block).
  • Download a specific version: Use this when a module requires a specific version for compatibility.
    • Run: composer require 'drupal/PROJECT_NAME:VERSION'
    • Example: composer require 'drupal/token:^1.5'
    • Note: On Windows, single quotes may cause "Could not parse version constraint" errors. Use double quotes "drupal/token:^1.5" or no quotes.
  • Using development versions: Dev versions are git clones and do not include Drupal.org version metadata. This means the Drupal core Update Manager may not function properly for them unless you install the Composer Deploy project. Use dev versions only as a temporary measure.

To use the module, you must still enable it via the Drupal admin UI (/admin/modules) or using Drush: drush en module_name. For example: drush en drupal/token.

Note: For Drupal 7 versioning and legacy mapping, see the Appendix.

Discovery commands

Use these to find and inspect packages without leaving the terminal:

  • Search: composer search <keyword> (e.g., composer search honey-pot).
  • Show versions: composer show drupal/recommended-project --all (Checks available core updates)
  • Browse: composer browse drupal/<keyword> (Opens the project page in your browser)

4. Advanced configuration

Customizing installation paths

To change where packages are downloaded (e.g., moving contributed code into /contrib or relocating the web root), modify the installer-paths section in composer.json. This uses the composer/installers package.

Example configuration:

"extra": {
  "installer-paths": {
    "web/core": ["type:drupal-core"],
    "web/libraries/{$name}": ["type:drupal-library"],
    "web/modules/contrib/{$name}": ["type:drupal-module"],
    "web/themes/contrib/{$name}": ["type:drupal-theme"],
    "web/modules/custom/{$name}": ["type:drupal-custom-module"]
  }
}

Warning: The first matching entry in installer-paths is used.
Custom paths: Custom module/theme paths require composer/installers v1.0.24+.

Managing third-party libraries (Asset Packagist)

Use Asset Packagist to manage JavaScript and CSS libraries (e.g., Leaflet, Slick, or Chosen) via Composer.

Note: This method is intended for PHP-based applications like Drupal. For decoupled or pure front-end projects, use native tools like NPM or Yarn.

Step 1: Initialize the Project

Run the following command to allow Composer to install packages to custom directories (like /libraries):

composer require oomphinc/composer-installers-extender

Step 2: Configure composer.json

Add the Asset Packagist repository and define the installation paths in your composer.json file.

Step 2.1. Add the repository
"repositories": [
    {
        "type": "composer",
        "url": "https://asset-packagist.org"
    }
]
2.2. Define installer types and paths

Add or append npm-asset and bower-asset to the extra section. This ensures libraries land in Drupal's /libraries folder instead of /vendor

"extra": {
    "installer-types": ["npm-asset", "bower-asset"],
    "installer-paths": {
        "web/libraries/{$name}": [
            "type:drupal-library",
            "type:npm-asset",
            "type:bower-asset"
        ]
    }
}

Step 3: Handle naming mismatches (optional)

If a package name (e.g., chosen-js) does not match the directory name a Drupal module expects (e.g., chosen), add a specific override above the general rule:

"installer-paths": {
    "web/libraries/chosen": ["npm-asset/chosen-js"],
    "web/libraries/{$name}": [
        "type:drupal-library",
        "type:npm-asset",
        "type:bower-asset"
    ]
}

Step 4: Require libraries

You can now require libraries using the npm-asset or bower-asset prefixes:

# Install a specific version of Leaflet
composer require bower-asset/leaflet:1.0.3

# Install Chosen JS
composer require npm-asset/chosen-js:^1.8

For more information, visit the official Asset Packagist site.


5. Patching projects

To apply community fixes automatically, use cweagans/composer-patches.

composer require cweagans/composer-patches:~2.0 --update-with-dependencies

Patch levels for modern Drupal

Because modern Drupal uses a /web subdirectory, you must specify the patch level in composer.json, or core patches will fail to apply. Without -p2, Composer will look in the wrong directory level.

"extra": {
    "patchLevel": {
        "drupal/core": "-p2",
        "drupal/contrib_module": "-p1"
    },
    "patches": {
        "drupal/core": {
            "Fix for issue X": "patches/fix-issue.patch"
        }
    }
}

Warning: Do not hotlink patches from Drupal.org. Download them and commit them to your local repository to prevent build failures if the remote file changes or is deleted.

Re-applying patches

If you add a patch to composer.json but do not change the version of the module, running composer install will not apply it. To force Composer to apply the new patch without updating the module version, use one of these methods:

  • Modern method: Use --lock to update the lock file metadata for a specific package: composer update drupal/core-recommended --lock
  • Universal/Legacy method: If the patch fails to trigger, delete the package folder and run install. This is the most reliable way to ensure a fresh, patched download.
    rm -rf vendor/drupal/package_name
    composer install

6. Maintenance & version control

Requiring a specific commit

If you need a specific fix in a development branch that hasn't been tagged yet:

  • Run: composer require drupal/PROJECT_NAME:VERSION#COMMIT_HASH
  • Example: composer require drupal/eck:1.x-dev#ecf376
  • Warning: The Composer team does not actively support commit references. composer validate will issue a warning, and this should only be a temporary solution.

Managing existing sites

If your site was originally installed without Composer (via zip/tarball):
Use the Composerize Drupal plugin to automatically generate a composer.json based on your existing codebase.
Alternatively, manually add the Drupal.org repository to your existing composer.json.

Git integration

  1. Copy the example gitignore and adjust for the /web subdirectory: cp web/example.gitignore .gitignore
  2. Adjust paths from sites/ to web/sites/ using: sed -i'.bak' -z 's|\nsites|\nweb/sites|g' .gitignore
  3. After running the sed command to adjust paths, ensure you remove the backup file created: rm .gitignore.bak

Note:The .gitignore should be at the same level as the vendor directory.

Standard .gitignore snippet

Ensure your .gitignore includes these core entries to prevent committing generated code or sensitive credentials:

# Ignore directories managed by Composer
/vendor/
/web/core/
/web/modules/contrib/
/web/themes/contrib/
/web/profiles/contrib/
/web/libraries/

# Ignore configuration and user-generated content
/web/sites/*/settings.php
/web/sites/*/services.yml
/web/sites/*/files/
/web/sites/*/private/

If you need to update a specific dependency (like Guzzle) beyond what core-recommended allows, you can switch to the less restrictive drupal/core:

  1. composer remove --no-update drupal/core-recommended
  2. composer require --update-with-all-dependencies drupal/core

Warning: This may update Guzzle from version 6 to 7, which can cause fatal errors in some code. Dependencies will no longer be locked to specific minor versions, so take care during future updates.

Review the instructions for managing Guzzle updates without drupal/core-recommended.


Appendix: semantic versioning shim

Drupal.org translates legacy version formats into Semantic Versioning (SemVer) for Composer compatibility.

Legacy Format Translated Format Example
{Platform.x}-{major}.{minor} {major}.{minor}.0 7.x-3.4 → 3.4.0
{7.x-major.x-dev} {major}.x-dev 7.x-1.x-dev → 1.x-dev
{Platform.x}-{major}.{minor}-{stability#} {major}.{minor}.0-{stability}{#} 7.x-3.4-beta2 → 3.4.0-beta2

Note: Unstable releases (e.g., 7.x-1.0-unstable3) are not translated and are unavailable to Composer.

Help improve this page

Page status: Needs work

You can: