Skip to main content

Composer

Composer is a dependency manager for PHP projects, including Drupal. It allows you to declare the libraries your project depends on and manages them for you.

This page covers the day-to-day workflows: requiring, updating, patching and auditing packages. It ends with a key-by-key reference of the shipped composer.json file.

Installing

To install packages, use composer require to include the package and resolve dependencies.

ahoy composer require drupal/devel

By default, stable releases are installed. If you need a non-stable version (e.g., alpha, beta, RC), specify the version constraint explicitly:

ahoy composer require drupal/devel:^1.0.0@beta

Make sure that the minimum-stability setting in composer.json is set to the version constraint you need. For example, to allow alpha, beta, and RC versions:

{
"minimum-stability": "beta"
}

Adding JavaScript/CSS libraries (npm packages)

To install JavaScript or CSS libraries as Drupal libraries with Composer, they must be defined as inline Composer packages. The package type for inline packages must be drupal-library, as Drupal treats these as libraries and places them into the web/libraries/ directory where it expects all libraries to reside.

Avoid Asset Packagist

Do not use Asset Packagist to install front-end libraries. Unlike Drupal.org, which maintains the distribution of Composer packages with established security policies, Asset Packagist is a third-party service that lacks the safeguards needed to protect against supply chain attacks. Instead, define packages as inline Composer packages as shown below.

  1. Define the package in composer.json under the repositories section:

    {
    "repositories": [
    {
    "type": "package",
    "package": {
    "name": "gdsmith/jquery.easing",
    "type": "drupal-library",
    "version": "1.4.1",
    "source": {
    "type": "git",
    "url": "https://github.com/gdsmith/jquery.easing",
    "reference": "1.4.1"
    }
    }
    }
    ]
    }
  2. Require the package using Composer:

ahoy composer require gdsmith/jquery.easing

Updating

To update all dependencies:

ahoy composer update
Updates and patches

If your project uses patches to modify dependencies, the update may fail if the patches are not compatible with the new versions of the dependencies.

A common solution is to remove the patches temporarily, run the update, and then reapply the patches one by one.

To update a specific package and its dependencies:

ahoy composer update vendor/package-name --with-dependencies

For updating Drupal core, use:

ahoy composer update "drupal/core-*" --with-dependencies

After updating core, review changes with git diff, especially modified scaffolding files like .htaccess, and commit them in a single commit.

Dependency bumping

Dependency bumping updates version constraints in your composer.json to match currently installed versions. This prevents accidental downgrades when adding new dependencies and improves dependency resolution performance.

Vortex enables this automatically via the bump-after-update configuration. Every time you run composer update, your version constraints are updated to reflect the installed versions.

note

Vortex enables automatic bumping because it's designed for application projects (Drupal sites) where you control the entire dependency tree. This keeps your version constraints synchronized with tested versions and prevents accidental downgrades.

This approach is not recommended for libraries (reusable packages). Libraries should keep version constraints as broad as possible to avoid dependency hell for downstream users. If you're building a library, use bump-after-update: "dev" to only bump development dependencies, or disable automatic bumping and run composer bump --dev-only manually.

Manual bumping

# Bump all dependencies
composer bump

# Bump specific package
composer bump drupal/core-recommended

# Bump only development dependencies
composer bump --dev-only

# Preview changes without modifying files
composer bump --dry-run

Overriding paths

To override package installation paths, modify composer.json:

{
"extra": {
"installer-paths": {
"web/libraries/jquery-easing": [
"gdsmith/jquery.easing"
],
"web/libraries/{$name}": [
"type:drupal-library"
]
}
}
}

The first entry overrides the path for a specific package, placing it into a custom directory name. The second entry is a catch-all that routes all drupal-library type packages to web/libraries/{$name} by default.

Vortex tooling package

Vortex ships its operational scripts - build, provision, deployment and notification tooling - as the drevops/vortex-tooling Composer package. The package is installed to vendor/drevops/vortex-tooling/src/ and exposes its entry-point scripts as Composer binaries under vendor/bin/vortex-*, such as vendor/bin/vortex-provision or vendor/bin/vortex-fetch-db.

See Architecture > Automation scripts for how the scripts are structured and how the router scripts dispatch to the provider-specific logic.

The package is required in composer.json with a tilde constraint:

{
"require": {
"drevops/vortex-tooling": "~1.4.0"
}
}

The ~ constraint accepts patch releases but holds the minor version, so a new minor release cannot reach your deployments until you raise the constraint yourself.

To update the package within the constraint:

ahoy composer update drevops/vortex-tooling

To move to a new minor release, raise the constraint in composer.json first and then run the update.

Never modify the shipped scripts

Do not modify files under vendor/drevops/vortex-tooling/src/ - the changes are lost on the next composer update. Customize the scripts through their environment variables or add your own scripts under scripts/ (for example, custom provision scripts). When neither is enough, apply a patch so the change survives dependency updates.

Patching

Vortex uses cweagans/composer-patches v2.x for applying patches to Composer dependencies. Version 2.x uses git-based patching with git apply for better cross-platform consistency.

tip

For official documentation, visit: Composer Patches Recommended Workflows

Understanding patches.lock.json

Composer Patches v2.x automatically generates a patches.lock.json file that contains:

  • Patch metadata (URLs, descriptions, target packages)
  • SHA-256 checksums for patch verification

This file must be committed to version control (like composer.lock).

Benefits:

  • Ensures reproducible builds across teams and CI/CD environments
  • Verifies patch integrity with checksums
  • Prevents "works on my machine" issues with patches
  • Makes the patch state explicit and trackable

Adding a new patch

  1. Define the patch in composer.json under extra.patches:

    "extra": {
    "patches": {
    "drupal/foobar": {
    "Fix for issue #123": "https://www.drupal.org/files/issues/fix-123.patch"
    }
    }
    }
  2. Regenerate patches.lock.json:

ahoy composer patches-relock
  1. Remove and reinstall patched packages:
ahoy composer patches-repatch
warning

composer patches-repatch removes patched dependencies from vendor/ and reinstalls them. Ensure you have no unsaved changes in those directories.

  1. Update composer.lock:
ahoy composer update --lock

Removing a patch

  1. Delete the patch definition from composer.json

  2. Regenerate patches.lock.json:

ahoy composer patches-relock
  1. Manually delete the affected dependency:
ahoy cli rm -rf vendor/drupal/foobar
  1. Reinstall without the patch:
ahoy composer patches-repatch
  1. Update composer.lock:
ahoy composer update --lock

Security auditing

composer audit checks the installed packages against published security advisories and reports abandoned packages. Vortex configures Composer's config.policy so that advisories never block composer install, composer update or composer require, while the composer audit command still fails when an advisory is found, keeping vulnerabilities visible locally and in CI.

➡️ See Dependency audit for the full policy reference, the audit commands, and ignoring assessed advisories.

composer.json reference

File overview

Vortex comes with a pre-configured composer.json that lists the dependencies a Drupal project needs, along with development tools to help you maintain your code quality.

The composer.json file is the core configuration file for Composer, detailing your project's dependencies, scripts, and settings.

This section provides an overview of each part of the composer.json file, explaining its role and how it contributes to your project's setup and management.

Click here to see the contents of the composer.json file
{
"name": "your_org/your_site",
"description": "Drupal 11 implementation of YOURSITE for YOURORG",
"license": "proprietary",
"type": "project",
"require": {
"php": ">=8.4",
"composer/installers": "^2.3",
"cweagans/composer-patches": "^2.0",
"drevops/vortex-tooling": "~1.4.0",
"drupal/clamav": "^2.1",
"drupal/coffee": "^2.0.1",
"drupal/config_split": "^2.0.2",
"drupal/config_update": "^2@alpha",
"drupal/core-composer-scaffold": "~11.4.5",
"drupal/core-recommended": "~11.4.5",
"drupal/devel": "^5.5",
"drupal/drupal_helpers": "^2.1.1",
"drupal/environment_indicator": "^4.0.25",
"drupal/generated_content": "^2.1.1",
"drupal/migrate_plus": "^6.0.10",
"drupal/migrate_tools": "^6.1.4",
"drupal/navigation_extra_tools": "^1.3.2",
"drupal/pathauto": "^1.15.0",
"drupal/redirect": "^1.13.0",
"drupal/redis": "^1.11",
"drupal/reroute_email": "^2.3@RC",
"drupal/robotstxt": "^1.6",
"drupal/sdc_devel": "^1.0.3",
"drupal/search_api": "^1.41.0",
"drupal/search_api_solr": "^4.4.0",
"drupal/seckit": "^2.0.3",
"drupal/shield": "^1.8",
"drupal/stage_file_proxy": "^4.0.0",
"drupal/testmode": "^2.7.2",
"drupal/xmlsitemap": "^2.0",
"drush/drush": "^13.7.6",
"webflo/drupal-finder": "^1.3.1"
},
"require-dev": {
"behat/behat": "^3.32.0",
"dantleech/gherkin-lint": "^0.2.4",
"dealerdirect/phpcodesniffer-composer-installer": "^1.2.1",
"drevops/behat-format-progress-fail": "^1.5.1",
"drevops/behat-screenshot": "^2.6.0",
"drevops/behat-steps": "^3.14.1",
"drevops/phpcs-standard": "^1.0.0",
"drupal/coder": "^9.0.1",
"drupal/drupal-extension": "^6.1",
"ergebnis/composer-normalize": "^2.52.0",
"lullabot/mink-selenium2-driver": "^1.7.4",
"lullabot/php-webdriver": "^2.0.7",
"mglaman/phpstan-drupal": "^2.1.2",
"mikey179/vfsstream": "^1.6.12",
"palantirnet/drupal-rector": "^1.1.2",
"phpcompatibility/php-compatibility": "^10.0@alpha",
"phpspec/prophecy-phpunit": "^2.5",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^2.2.8",
"phpunit/phpunit": "^11.5.56",
"pyrech/composer-changelogs": "^2.2",
"rector/rector": "^2.6.3",
"softcreatr/jsonpath": "^0.10 || ^1.0",
"vincentlanglet/twig-cs-fixer": "^4.0.2"
},
"conflict": {
"drupal/drupal": "*"
},
"repositories": [
{
"type": "composer",
"url": "https://packages.drupal.org/8"
},
{
"type": "path",
"url": ".vortex/tooling",
"options": {
"versions": {
"drevops/vortex-tooling": "1.4.0"
}
}
}
],
"minimum-stability": "stable",
"prefer-stable": true,
"autoload-dev": {
"classmap": [
"tests/phpunit/"
]
},
"config": {
"allow-plugins": {
"composer/installers": true,
"cweagans/composer-patches": true,
"dealerdirect/phpcodesniffer-composer-installer": true,
"drupal/core-composer-scaffold": true,
"ergebnis/composer-normalize": true,
"php-http/discovery": true,
"phpstan/extension-installer": true,
"pyrech/composer-changelogs": true,
"symfony/runtime": true,
"tbachert/spi": true
},
"bump-after-update": true,
"discard-changes": true,
"platform": {
"php": "8.4.23"
},
"policy": {
"advisories": {
"block": false,
"audit": "fail"
},
"abandoned": {
"audit": "report"
}
},
"sort-packages": true
},
"extra": {
"drupal-scaffold": {
"file-mapping": {
"[project-root]/.editorconfig": false,
"[project-root]/.gitattributes": false,
"[web-root]/.csslintrc": false,
"[web-root]/.eslintignore": false,
"[web-root]/.eslintrc.json": false,
"[web-root]/.ht.router.php": false,
"[web-root]/.htaccess": false,
"[web-root]/INSTALL.txt": false,
"[web-root]/README.md": false,
"[web-root]/example.gitignore": false,
"[web-root]/robots.txt": false,
"[web-root]/sites/example.settings.local.php": false,
"[web-root]/sites/example.sites.php": false,
"[web-root]/update.php": false
},
"locations": {
"web-root": "web/"
}
},
"installer-paths": {
"web/core": [
"type:drupal-core"
],
"web/libraries/{$name}": [
"type:drupal-library"
],
"web/modules/contrib/{$name}": [
"type:drupal-module"
],
"web/profiles/contrib/{$name}": [
"type:drupal-profile"
],
"recipes/{$name}": [
"type:drupal-recipe"
],
"web/themes/contrib/{$name}": [
"type:drupal-theme"
],
"drush/Commands/contrib/{$name}": [
"type:drupal-drush"
],
"web/modules/custom/{$name}": [
"type:drupal-custom-module"
],
"web/profiles/custom/{$name}": [
"type:drupal-custom-profile"
],
"web/themes/custom/{$name}": [
"type:drupal-custom-theme"
]
},
"patchLevel": {
"drupal/core": "-p2"
},
"patches": {}
}
}

name

name is a unique identifier for the project in Composer's ecosystem consisting of a vendor name and the project's name.

description

A brief summary of the project's purpose.

type

type is used to specify the type of the package. This is important because it tells Composer and any systems integrating with Composer how to treat the package. The type key can influence how the package is installed and used.

license

license indicates the license of the project. Since Vortex is a template for your consumer sites that are usually proprietary, we use proprietary as the default value. More license identifiers are listed at the SPDX Open Source License Registry.

repositories

The repositories section defines custom package repositories, needed for accessing packages outside the default Packagist repository.

RepositoryTypeDescription
packages.drupal.org/8composerThe official source for Drupal modules, themes and distributions, which are not published on Packagist.
.vortex/toolingpathResolves the in-tree tooling package while developing Vortex itself. The installer removes this entry during site creation, so your project installs drevops/vortex-tooling from Packagist instead.

require

The require section specifies the packages and libraries your project needs.

The Documentation column links to the page covering that package in more depth. A Settings link means Vortex ships a per-module override file that applies environment-aware defaults for that module. Some modules still need a running service or environment-specific values on top of those defaults.

➡️ See Contributed modules for what each override actually configures and where each module is installed.

PackageDescriptionDocumentation
phpThe minimum PHP version required to run this project. Specify a range such as >=8.4 rather than an exact version such as 8.4.0.
composer/installersInstalls packages into the correct location based on their package type, such as drupal-module, drupal-theme or drupal-profile.
cweagans/composer-patchesPatches Composer packages with git apply, incorporating fixes that are not yet in an official release. Patch metadata and SHA-256 checksums are recorded in patches.lock.json for reproducible builds.Patching
drevops/vortex-toolingShips the Vortex operational scripts - build, provision, deployment and notification tooling - that your site runs from vendor/drevops/vortex-tooling/src/.Vortex tooling package
drupal/clamavScans uploaded files for malware with the ClamAV engine before they are saved.Settings
drupal/coffeeAdds a keyboard shortcut to jump straight to any administration page by typing its name.
drupal/config_splitSplits configuration into sets that are conditionally imported, enabling environment-specific configuration such as development-only modules.Settings
drupal/config_updateProvides tools and Drush commands to report, revert and import configuration changes relative to the defaults shipped by modules.
drupal/core-composer-scaffoldDownloads Drupal Scaffold files such as index.php and update.php from the drupal/core project and places them inside the web root.
drupal/core-recommendedPins the set of dependency versions that the Drupal community tests and recommends for a particular core version, ensuring compatibility and stability.
drupal/develA suite of development tools for inspecting variables, entities and the service container while debugging.Settings
drupal/drupal_helpersA collection of helper functions that simplify writing update hooks and deployment operations.Drupal helpers
drupal/environment_indicatorShows a colored banner identifying the current environment to prevent accidental changes on the wrong site.Settings
drupal/generated_contentGenerates deterministic placeholder content from declarative definitions for development and testing.Generated content, Settings
drupal/migrate_plusExtends the core Migrate API with extra source and process plugins and configuration-entity migrations.Migrations
drupal/migrate_toolsProvides Drush commands and a UI to run, roll back and monitor migrations.Migrations
drupal/navigation_extra_toolsAdds administration shortcuts - clear caches, run cron, run database updates - to the core Navigation module.
drupal/pathautoAutomatically generates URL aliases for content based on configurable patterns.
drupal/redirectManages URL redirects and creates them automatically when content URLs change.
drupal/redisIntegrates Drupal with the Redis in-memory store for cache and lock backends.Settings
drupal/reroute_emailReroutes all outbound email to a configured address on non-production environments to avoid emailing real users.Settings
drupal/robotstxtManages the robots.txt file from the admin UI, useful when it cannot be placed on disk (for example, in multisite setups).Settings
drupal/sdc_develDevelopment and validation tooling for Single Directory Components (SDC), reporting issues in component definitions and templates.
drupal/search_apiProvides a framework for building search experiences with pluggable indexing backends.
drupal/search_api_solrA Search API backend that integrates Apache Solr for fast, scalable search.
drupal/seckitAdds configurable security-hardening HTTP headers, including Content Security Policy and anti-framing protection.Settings
drupal/shieldProtects non-production environments behind HTTP basic authentication.Settings
drupal/stage_file_proxyFetches media files from a remote site on demand, so local environments do not need a full copy of the files directory.Settings
drupal/testmodeAdjusts site behavior during automated tests, for example by filtering out generated content from listings.Testmode, Settings
drupal/xmlsitemapGenerates a multilingual XML sitemap to help search engines index the site.Settings
drush/drushA command-line shell and scripting interface for Drupal, providing a wide range of utilities to manage and interact with your Drupal sites.Drush
webflo/drupal-finderLocates Drupal installations in a directory structure.

require-dev

The require-dev section lists packages used for development purposes, like code quality checks and testing. These tools are needed during development but not in production environments, so the production deployment stays smaller while the development environment keeps its full tooling.

PackageDescriptionDocumentation
behat/behatA PHP framework for Behavior-Driven Development (BDD), running human-readable stories that describe the behavior of your application. It facilitates communication between developers, stakeholders and clients.Behat
dantleech/gherkin-lintLints the Gherkin feature files used in Behat tests, checking syntax and formatting for consistency.Gherkin Lint
dealerdirect/phpcodesniffer-composer-installerRegisters the coding standards installed through Composer with PHP_CodeSniffer, so they can be referenced by name.PHPCS
drevops/behat-format-progress-failA Behat output formatter that prints compact progress and expands the detail only for failing scenarios.Behat
drevops/behat-screenshotAutomatically captures a screenshot when a Behat scenario fails, which helps to understand why a test failed.Behat
drevops/behat-stepsA collection of pre-defined Behat step definitions for Drupal, speeding up the process of writing new tests.Behat
drevops/phpcs-standardA PHP_CodeSniffer coding standard that extends the Drupal coding standards with additional rules and best practices.PHPCS
drupal/coderProvides the PHP_CodeSniffer rules for the Drupal coding standards. The 9.x line targets PHP_CodeSniffer 4.x.PHPCS
drupal/drupal-extensionA Behat extension that integrates with Drupal, offering Drupal-specific step definitions and bootstrapping the site for testing.Behat
ergebnis/composer-normalizeA Composer plugin that normalizes the formatting and key order of composer.json.
lullabot/mink-selenium2-driverA maintained fork of the Mink Selenium2 driver that lets Behat control real browsers through Selenium WebDriver.Behat
lullabot/php-webdriverA maintained fork of the PHP WebDriver client used by the Mink Selenium2 driver to communicate with browsers.Behat
mglaman/phpstan-drupalTeaches PHPStan about Drupal APIs, so static analysis understands hooks, services and entities in modules and themes.PHPStan
mikey179/vfsstreamA virtual file system for PHPUnit tests, allowing file operations to be exercised without touching the real file system.PHPUnit
palantirnet/drupal-rectorRector rules that rewrite deprecated Drupal code, making core upgrades more efficient.Rector
phpcompatibility/php-compatibilityPHP_CodeSniffer sniffs that check code for compatibility with specific PHP versions. The 10.x line targets PHP_CodeSniffer 4.x.PHPCS
phpspec/prophecy-phpunitIntegrates the Prophecy mocking library with PHPUnit to provide advanced mocking capabilities in tests.PHPUnit
phpstan/extension-installerAutomatically registers the installed PHPStan extensions, removing the need to wire them up by hand.PHPStan
phpstan/phpstanA static analysis tool that finds type errors, incorrect method calls and other bugs without running the code.PHPStan
phpunit/phpunitThe PHP testing framework, used here for unit, kernel and functional tests.PHPUnit
pyrech/composer-changelogsPrints a summary of package additions, updates and removals after running composer update.
rector/rectorAn automated refactoring tool that upgrades and modernizes PHP code.Rector
softcreatr/jsonpathA JSONPath implementation required by the drevops/behat-steps JSON assertion steps.Behat
vincentlanglet/twig-cs-fixerChecks and fixes Twig templates against a coding standard, keeping template files consistent and readable.Twig CS Fixer

conflict

The conflict section prevents installation conflicts with standalone Drupal core, which matters for avoiding version clashes and ensuring consistency in core files.

minimum-stability

The minimum-stability setting controls the minimum stability level of the packages that Composer is allowed to install. By setting it to "stable", you are instructing Composer to prefer stable versions of packages over their unstable (like beta or alpha) versions.

prefer-stable

The prefer-stable settings, when set to true, instructs Composer to prefer stable versions of packages even when the minimum-stability setting allows less stable versions. This is especially useful in a mixed stability scenario where some dependencies might not have a stable release yet. It ensures that Composer will use stable versions wherever possible, thus providing a balance between stability and the need for newer features or fixes that might only be available in a less stable package version.

config

The config section specifies key configurations for Composer's behavior in the project.

  • allow-plugins: This setting specifies which Composer plugins are allowed to run. It's a security measure to prevent the execution of untrusted code from third-party plugins. Each plugin needs to be explicitly allowed to ensure it can execute.
  • policy: Introduced in Composer 2.10.0, this unified setting controls security auditing and version blocking of dependencies. Vortex configures it so that advisories never block installs but still fail composer audit, keeping vulnerabilities visible without breaking reproducible builds. ➡️ See Security auditing for the option values, ignoring advisories, and the CI integration.
  • bump-after-update: Automatically updates version constraints in composer.json to match currently installed package versions after running composer update. Vortex sets this to true to bump all dependencies, ensuring version constraints stay in sync with installed versions. Available values: true (all dependencies), false (disabled), "dev" (only dev dependencies), or "no-dev" (only non-dev dependencies).
  • discard-changes: When set to true, any local changes made to the dependencies (packages under version control like Git) are discarded without prompting when you run composer install or composer update. Composer will overwrite the local changes with the data from the source repository.
  • platform: Specifies the PHP version of the platform environment where the current project runs. This should be specified as an exact version number (e.g. 8.4.23). It should be kept in sync with the php version in the Docker containers.
  • sort-packages: When set to true, this configuration ensures that packages are sorted in composer.json and composer.lock. It makes these files more readable and helps reduce merge conflicts in version control.

autoload-dev

The autoload-dev section defines how Composer automatically loads PHP development-specific classes within the project, without needing to manually include or require each class file.

extra

The extra section serves as a source of custom configuration for various packages. These packages read settings from this section to tailor their behavior according to the specific needs and structure of your Drupal project.

  • drupal-scaffold: This setting controls which files should be scaffolded:
    • locations: Specifies the location of the web root (the directory containing the index.php file).
    • file-mapping: Determines which files are managed by the scaffold process. Vortex comes with sensible defaults, but you can customize this section to suit your needs.
  • installer-paths: Defines custom installation paths for various types of packages like Drupal modules, themes, and libraries.
  • patchLevel: Defines the patch level for specific packages, in this case, drupal/core. The -p option followed by a number (e.g., -p1, -p2) in patch commands specifies the number of leading directories to strip from the file paths found in the patch file. This determines how the paths in the patch file are interpreted relative to the current directory where the patch is being applied.
  • patches: Specifies the patches to be applied to specific packages. The applied patch state lives in the generated patches.lock.json file, which is committed like composer.lock. ➡️ See Patching