Skip to main content
Version: v2

Composer

Composer is the dependency manager for PHP, and Drupal projects use it for everything from core to contributed modules. You declare the packages your project needs in composer.json, and Composer resolves compatible versions, installs them, and records the exact result in composer.lock.

This page is for developers who manage the packages of a project built from Vortex. It shows you how to require, update, patch, and audit packages, and it ends with a key-by-key reference of the shipped composer.json file.

Installing​

Add a package with composer require. Composer adds it to composer.json, resolves its dependencies, and installs the package along with them. To add the Devel module, for example, run the following command:

ahoy composer require drupal/devel

By default, Composer installs only stable releases. To install a pre-release of a package, such as an alpha, beta, or RC, add a stability flag to its version constraint:

ahoy composer require drupal/devel:^1.0.0@beta

The flag applies to that package alone. When the pre-release needs unstable versions of its own dependencies, require each of them with a flag too, or lower minimum-stability in composer.json. A stability level allows itself and everything more stable, so beta allows beta, RC, and stable releases, but not alpha or dev:

{
"minimum-stability": "beta"
}

Keep prefer-stable set to true, as Vortex ships it, so Composer still picks a stable release wherever one satisfies the constraint.

Adding JavaScript/CSS libraries (npm packages)​

To install a JavaScript or CSS library as a Drupal library with Composer, define it as an inline Composer package with the drupal-library type. The installer-paths entry for that type puts it in web/libraries/, where Drupal looks for libraries.

Avoid Asset Packagist

Don't use Asset Packagist to install front-end libraries. Drupal.org distributes its Composer packages under established security policies, while Asset Packagist is a third-party service without the safeguards that protect against supply chain attacks. Define the packages inline instead, as the following steps show.

To add the jQuery Easing library, for example, follow these steps:

  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

Confirm that the library's files are in web/libraries/jquery.easing/.

Updating​

To update all dependencies, run the following command:

ahoy composer update
Updates and patches

If your project patches its dependencies, an update can fail when a patch no longer applies to the new version of a dependency. Composer then stops with No available patcher was able to apply patch, followed by the patch URL and the package name.

A common fix 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, run the following command:

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

To update Drupal core, run the following command:

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

Review the result with git diff and commit it as a single commit. Look closely at the scaffold files that core updates, such as web/index.php and web/sites/default/default.settings.php. Vortex ships its own web/.htaccess and keeps it out of scaffolding, so a core update never overwrites it. When a core release changes .htaccess, port the change by hand.

Dependency bumping​

Dependency bumping raises the version constraints in composer.json to the versions you have installed. That keeps a new dependency from dragging an installed package back to an older version, and it gives Composer fewer versions to consider, which speeds up dependency resolution.

Vortex turns this on with the bump-after-update setting, so every composer update raises your constraints to the versions it installed.

note

Vortex bumps automatically because it's built for application projects (Drupal sites), where you control the whole dependency tree.

Bumping doesn't suit libraries (reusable packages). A library should keep its constraints as broad as possible to spare downstream users dependency hell. If you're building a library, set bump-after-update: "dev" to bump only the development dependencies, or turn automatic bumping off and run composer bump --dev-only yourself.

Manual bumping​

The following commands bump the constraints by hand:

# 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

Run them in the cli container, or prefix them with ahoy, as in ahoy composer bump.

Overriding paths​

To install a package somewhere other than the default location for its type, add an entry to installer-paths in composer.json:

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

The first entry sends 1 package to a custom directory. The second is the catch-all that routes every other drupal-library package to web/libraries/{$name}. Composer uses the first entry that matches, so a package-specific path must come before the catch-all for its type.

Vortex tooling package​

Vortex ships its operational scripts, such as the database, provisioning, deployment, and notification scripts, as the drevops/vortex-tooling Composer package. The scripts live in vendor/drevops/vortex-tooling/src/, and Composer exposes each entry-point script as a binary 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.

composer.json requires the package with a caret constraint and an @alpha stability flag:

{
"require": {
"drevops/vortex-tooling": "^2.0@alpha"
}
}

The ^2.0 constraint accepts every 2.x release, so composer update brings in new minor and patch releases but never a 3.x release. The @alpha flag lets Composer install a 2.x pre-release while no stable release exists.

The major version in this constraint also identifies the Vortex major of your project. The Vortex CLI reads it and stops with an error when the project's major differs from its own.

To update the package within the constraint, run the following command:

ahoy composer update drevops/vortex-tooling
Never modify the shipped scripts

Don't edit files under vendor/drevops/vortex-tooling/src/. Git ignores vendor/, so your changes never reach the repository, and Composer replaces the files whenever it reinstalls or updates the package. Customize the scripts through their environment variables or add your own scripts under scripts/. Logic that runs on every deploy goes in a deploy step. When none of these is enough, apply a patch, which Composer applies again whenever it installs or updates the package.

Patching​

Vortex patches Composer dependencies with cweagans/composer-patches 2.x. Version 2.x applies patches with git apply, so they behave the same on every platform. For the official documentation, see Composer Patches Recommended Workflows.

Understanding patches.lock.json​

Composer Patches 2.x generates a patches.lock.json file. For each patch, the file records the following:

  • The package it applies to, its description, and its URL
  • A SHA-256 checksum of the patch file
  • The depth used to apply it

Commit this file to version control, like composer.lock. It makes builds reproducible across your team and in CI/CD: the patch state stays explicit and trackable, and the checksums in the file verify each patch's integrity.

Adding a new patch​

To add a patch, follow these steps:

  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

The output ends with patches.lock.json has been recreated successfully.

warning

composer patches-repatch uninstalls every patched package from wherever it's installed, such as web/modules/contrib/ or vendor/, and then runs composer install to put it back. Any local edits in those packages are lost.

  1. Remove and reinstall patched packages:
ahoy composer patches-repatch
  1. Update composer.lock:
ahoy composer update --lock

Confirm that the patches-repatch output in step 3 has a - Patching drupal/foobar line for the patched package.

Removing a patch​

To remove a patch, follow these steps:

  1. Delete the patch definition from composer.json.

  2. Regenerate patches.lock.json:

ahoy composer patches-relock
  1. Delete the package's directory by hand, because patches-repatch only reinstalls packages that still have patches:
ahoy cli rm -rf web/modules/contrib/foobar
  1. Reinstall without the patch:
ahoy composer patches-repatch
  1. Update composer.lock:
ahoy composer update --lock

Confirm that patches.lock.json no longer lists the package, unless it still has other patches.

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. composer audit itself still fails when it finds an advisory, so vulnerabilities stay 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 ships a pre-configured composer.json with the packages a Drupal project needs and the development tools that check your code quality.

The composer.json file is Composer's core configuration file: it declares your project's dependencies, where they install, and how Composer behaves. The lint job in continuous integration checks it with composer validate --strict and composer normalize --dry-run, so run ahoy composer normalize after you edit it by hand.

This section describes each part of the file and its role.

Expand to see composer.json
{
"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/environment-detector": "~0.6.0",
"drevops/vortex-tooling": "^2.0@alpha",
"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.11",
"drupal/core-recommended": "~11.4.11",
"drupal/deploy_steps": "^1.0.0-alpha1",
"drupal/devel": "^5.5",
"drupal/drupal_helpers": "^2.2.0",
"drupal/environment_indicator": "^4.0.25",
"drupal/fast_404": "^3.7",
"drupal/generated_content": "^2.2.0",
"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.42.0",
"drupal/search_api_solr": "^4.4.0",
"drupal/seckit": "^2.0.3",
"drupal/shield": "^1.10",
"drupal/stage_file_proxy": "^4.0.0",
"drupal/storybook": "^1.0.4",
"drupal/testmode": "^2.8.0",
"drupal/xmlsitemap": "^2.0",
"drush/drush": "^13.8.0"
},
"require-dev": {
"behat/behat": "^4.0.0",
"dantleech/gherkin-lint": "^0.2.4",
"drevops/behat-screenshot": "^3.0.0",
"drevops/behat-steps": "^4.0@rc",
"drevops/phpcs-standard": "^1.1.0",
"drupal/coder": "^9.0.1",
"ergebnis/composer-normalize": "^2.54.0",
"friends-of-behat/mink-extension": "^3.0@alpha",
"lullabot/mink-selenium2-driver": "^1.7.4",
"mglaman/phpstan-drupal": "^2.2.2",
"mikey179/vfsstream": "^1.6.12",
"palantirnet/drupal-rector": "^1.1.3",
"phpcompatibility/php-compatibility": "^10.0@alpha",
"phpspec/prophecy-phpunit": "^2.5",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^2.3.1",
"phpunit/phpunit": "^11.5.57",
"pyrech/composer-changelogs": "^2.2",
"softcreatr/jsonpath": "^0.10 || ^1.0",
"vincentlanglet/twig-cs-fixer": "^4.1.1"
},
"conflict": {
"drupal/drupal": "*"
},
"repositories": [
{
"type": "composer",
"url": "https://packages.drupal.org/8"
},
{
"type": "path",
"url": ".vortex/tooling",
"options": {
"versions": {
"drevops/vortex-tooling": "2.0.0-alpha1"
}
}
}
],
"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.27"
},
"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 identifies the project in Composer's ecosystem, as a vendor name and a project name joined by a slash. The CLI replaces the template's your_org/your_site with your organization and site machine names.

description​

A short summary of the project's purpose. The CLI fills in your site and organization names.

type​

type sets how Composer, and any system that integrates with it, treats the package, which can change how it's installed and used. Vortex sets it to project, the type for an application rather than a reusable library.

license​

license states the project's license. Vortex sets it to proprietary, because the sites built from the template are usually proprietary. The SPDX Open Source License Registry lists the identifiers for other licenses.

repositories​

The repositories section adds package repositories beyond Packagist, the default one. The template declares the following 2 repositories:

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

require​

The require section lists the packages your project needs to run.

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.

Not every package reaches your project. The CLI handles these packages based on your answers:

  • It leaves out drupal/storybook, drupal/migrate_plus, and drupal/migrate_tools unless you turn on Storybook or the migration database.
  • It drops the module of each service you deselect: drupal/clamav, drupal/redis, or drupal/search_api_solr.
  • It lets you deselect any of the other contributed modules except drupal/search_api and drupal/deploy_steps, which always stay.

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

The following table describes each package in require:

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.None
composer/installersInstalls packages into the correct location based on their package type, such as drupal-module, drupal-theme, or drupal-profile.None
cweagans/composer-patchesPatches Composer packages with git apply, incorporating fixes that aren't yet in an official release. Patch metadata and SHA-256 checksums are recorded in patches.lock.json for reproducible builds.Patching
drevops/environment-detectorDetects the hosting platform or CI service and the environment type, and applies that platform's Drupal settings.Settings
drevops/vortex-toolingShips the Vortex operational scripts, such as the database, provisioning, deployment, and notification scripts, in vendor/drevops/vortex-tooling/src/.Vortex tooling package
drupal/clamavScans uploaded files for malware with the ClamAV engine before they're saved.Settings
drupal/coffeeAdds a keyboard shortcut to jump straight to any administration page by typing its name.None
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.None
drupal/core-composer-scaffoldCopies Drupal's scaffold files, such as index.php and sites/default/default.settings.php, from the drupal/core package into the web root. The drupal-scaffold settings choose which files it manages.None
drupal/core-recommendedPins the set of dependency versions that the Drupal community tests and recommends for a particular core version.None
drupal/deploy_stepsRuns the DeployStep plugins of enabled modules before and after the drush deploy:hook body on every deploy. The provision script enables it.Provision
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/fast_404Answers requests for missing files with a 404 before Drupal bootstraps, saving the bootstrap that core's own fast 404 still performs.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.None
drupal/pathautoAutomatically generates URL aliases for content based on configurable patterns.None
drupal/redirectManages URL redirects and creates them automatically when content URLs change.None
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 can't be placed on disk (for example, in multisite setups). Vortex leaves core's robots.txt out of scaffolding, so this module serves the file.Settings
drupal/sdc_develDevelopment and validation tooling for Single Directory Components (SDC), reporting issues in component definitions and templates.SDC Devel, Settings
drupal/search_apiProvides a framework for building search experiences with pluggable indexing backends.None
drupal/search_api_solrA Search API backend that indexes and searches content in Apache Solr.None
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 don't need a full copy of the files directory.Settings
drupal/storybookRenders the custom theme's Twig stories through Drupal for the Storybook component library, so the library shows the same markup the site renders.Storybook, Settings
drupal/testmodeFilters the listings in registered views down to test content while test mode is on, which keeps live and generated content out of Behat assertions.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

require-dev​

The require-dev section lists packages you need only during development, such as the code quality and testing tools. The container image build runs composer install --no-dev, so none of them reach production and the deployment stays smaller. The CLI removes the packages of each development tool you deselect, with 2 exceptions: softcreatr/jsonpath stays when you deselect Behat, and mikey179/vfsstream stays when you deselect PHPUnit.

The following table describes each package in require-dev:

PackageDescriptionDocumentation
behat/behatA PHP framework for Behavior-Driven Development (BDD) that runs human-readable scenarios describing how your application behaves. The scenarios double as a shared description of the site for developers, stakeholders, and clients.Behat
dantleech/gherkin-lintLints the Gherkin feature files used in Behat tests, checking syntax and formatting for consistency.Gherkin Lint
drevops/behat-screenshotCaptures HTML and PNG screenshots on demand and whenever a scenario fails, and combines per-step screenshots into an animated GIF for each scenario.Behat
drevops/behat-stepsProvides the Behat extension that integrates the tests with Drupal, and a library of ready-made step definitions for Drupal sites.Behat
drevops/phpcs-standardA PHP_CodeSniffer standard that checks the naming of local variables and parameters, snake case by default, and the naming and order of PHPUnit data providers. phpcs.xml applies it alongside the Drupal standards.PHPCS
drupal/coderProvides the PHP_CodeSniffer rules for the Drupal coding standards. The 9.x line targets PHP_CodeSniffer 4.x.PHPCS
ergebnis/composer-normalizeA Composer plugin that normalizes the formatting and key order of composer.json. The CI lint job runs composer normalize --dry-run and fails on a file that isn't normalized.None
friends-of-behat/mink-extensionConnects Behat to Mink, providing the browser sessions and the base browser steps. Behat 4 needs its 3.x line, which composer.json requires as ^3.0@alpha.Behat
lullabot/mink-selenium2-driverThe Mink driver that controls a browser through a Selenium or WebDriver server. Behat uses it for scenarios tagged @javascript, and Drupal core's functional JavaScript tests build on it too. The CLI removes it when you deselect Behat, even if you keep PHPUnit, so the functional JavaScript tests then need it required again.Behat
mglaman/phpstan-drupalAdds Drupal support to PHPStan, so static analysis covers the 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. It installs rector/rector and constrains it to the versions its rule sets support.Rector
phpcompatibility/php-compatibilityPHP_CodeSniffer sniffs that check code for compatibility with specific PHP versions. The 10.x line adds support for PHP_CodeSniffer 4.x and is required with the @alpha stability flag.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 the unit, kernel, functional, and functional JavaScript tests.PHPUnit
pyrech/composer-changelogsPrints a summary of package additions, updates, and removals after running composer update.None
softcreatr/jsonpathA JSONPath implementation required by the drevops/behat-steps JSON assertion steps. The CLI's Behat removal leaves it out, so it stays when you deselect Behat, although nothing else uses it.Behat
vincentlanglet/twig-cs-fixerChecks and fixes Twig templates against a coding standard.Twig CS Fixer

conflict​

The conflict section declares every version of drupal/drupal, the standalone Drupal package, incompatible with the project. Composer refuses to install it next to the core packages, so core versions don't clash and core files stay consistent.

minimum-stability​

The minimum-stability setting is the lowest stability that Composer accepts when it resolves dependencies. Vortex sets it to "stable", so Composer ignores the pre-releases of every package unless its constraint in require or require-dev carries a stability flag. For example, "friends-of-behat/mink-extension": "^3.0@alpha" lets that package install as an alpha.

prefer-stable​

The prefer-stable setting, when set to true, makes Composer choose a stable release over a pre-release whenever a stable one satisfies the constraint. A requirement with a stability flag, such as "drupal/config_update": "^2@alpha", then gets an alpha only while no stable 2.x release exists. The same applies when you lower minimum-stability to reach a feature or fix that's only in a pre-release: every package that has a stable release keeps getting one.

config​

The config section configures how Composer behaves in the project. Vortex sets the following keys:

  • allow-plugins: Lists the Composer plugins that are allowed to run. Composer doesn't run a plugin that isn't listed, which protects you from untrusted code in third-party plugins. Vortex allows these 10 plugins:
    • composer/installers
    • cweagans/composer-patches
    • dealerdirect/phpcodesniffer-composer-installer
    • drupal/core-composer-scaffold
    • ergebnis/composer-normalize
    • php-http/discovery
    • phpstan/extension-installer
    • pyrech/composer-changelogs
    • symfony/runtime
    • tbachert/spi
  • policy: Controls security auditing and version blocking of dependencies, and requires Composer 2.10.0 or later. Vortex sets advisories.block to false, advisories.audit to "fail", and abandoned.audit to "report". Advisories never block installs but still fail composer audit, so vulnerabilities stay visible without breaking reproducible builds, and abandoned packages show up in the report without failing it. ➡️ See Dependency audit for the option values, ignoring advisories, and the CI integration.
  • bump-after-update: Runs composer bump after every composer update, which raises the version constraints in composer.json to the installed versions. Vortex sets it to true to bump all dependencies. The available values are true (all dependencies), false (disabled), "dev" (only development dependencies), and "no-dev" (only non-development dependencies).
  • discard-changes: When set to true, Composer discards local changes in dependencies that were installed from source, such as a Git checkout. The setting applies only when Composer runs non-interactively, for example in CI or with --no-interaction; an interactive run asks you what to do.
  • platform: Tells Composer which PHP version to resolve dependencies for, regardless of the PHP version that runs Composer. Set it as an exact version number, such as the 8.4.27 that Vortex ships, and keep it in sync with the PHP version in the Docker containers.
  • sort-packages: When set to true, composer require keeps the package lists in composer.json sorted by name. Sorted lists are easier to read and cause fewer merge conflicts. The setting doesn't affect composer.lock.

autoload-dev​

The autoload-dev section tells Composer how to autoload the classes that only development needs, so no file has to include or require them by hand. Vortex adds tests/phpunit/ to its classmap, which covers the project-level PHPUnit tests, such as the settings tests, and their base classes.

extra​

The extra section holds configuration for Composer plugins, which read their settings from here to fit the structure of your Drupal project. Vortex sets the following keys:

  • drupal-scaffold: Controls the Drupal scaffold files:

    • locations: Sets the web root (the directory containing the index.php file), web/ in Vortex.
    • file-mapping: Decides which scaffold files the plugin manages. Vortex turns off 14 of the files that core provides: it ships its own .htaccess, .editorconfig, and .gitattributes, and leaves out others such as update.php and robots.txt. Set an entry to false to stop core from overwriting that file.
  • installer-paths: Sets where each package type installs:

    • Drupal core: web/core
    • Contributed modules, themes, and profiles: web/modules/contrib, web/themes/contrib, and web/profiles/contrib
    • Custom modules, themes, and profiles: web/modules/custom, web/themes/custom, and web/profiles/custom
    • Libraries: web/libraries
    • Recipes: recipes
    • Drush command packages: drush/Commands/contrib

    ➡️ See Overriding paths

  • patchLevel: Sets -p2 for drupal/core. The -p option of a patch command (for example, -p1 or -p2) is the number of leading directories to strip from the file paths in the patch. Version 2.x of cweagans/composer-patches doesn't read this key. It takes the depth from the first of these that's set:

    • The patch's own depth
    • extra.composer-patches.package-depths for the package
    • Its built-in default for the package, which is 2 for drupal/core
    • extra.composer-patches.default-patch-depth, which defaults to 1
  • patches: Lists the patches to apply to each package, and it's empty in the template. The applied patch state lives in the generated patches.lock.json file, which you commit like composer.lock. ➡️ See Patching