Contributed modules
Vortex ships the contributed modules most Drupal projects need, each pre-configured and wired into the environment-aware settings and the provisioning deploy steps. This page lists every shipped module in alphabetical order: what it does, why it ships, how it's installed, and how it's configured.
It's a reference for developers and leads on a project built from Vortex. Use it to check what a module does in each environment and which variables change that.
Most modules are installed by EnableDevelopmentModulesDeployStep, a
deploy step in the ys_base module. It runs on every deployment in every
environment except production.
➡️ See Overview for the mechanisms that require, configure, and install these modules.
ClamAV
ClamAV scans uploaded files for malware with the ClamAV engine before they're saved. Ships only when the ClamAV service is selected.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step, which also savesclamavas the daemon host in the module configuration.
Configuration
settings.clamav.php
selects daemon or executable mode and points the daemon at the ClamAV
service, but only when DRUPAL_CLAMAV_ENABLED is set to 1. The shipped
.env file sets it, with DRUPAL_CLAMAV_MODE set to daemon. Executable
mode calls ClamAV's command-line scanner in /usr/bin instead of the
daemon.
The override reads the following variables:
| Variable | Purpose |
|---|---|
DRUPAL_CLAMAV_ENABLED | Applies the override only when set to 1 |
DRUPAL_CLAMAV_MODE | daemon (any case) or 0 selects daemon mode; any other value, or none, selects executable mode |
CLAMAV_HOST, CLAMAV_PORT | Daemon host and port, antivirus:3310 by default |
Coffee
Coffee adds a search box, opened with Alt+D, that jumps straight to any administration page as you type its name.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
No settings override.
Config Split
Configuration Split splits configuration into sets that are imported conditionally, so each environment can carry its own configuration, such as development-only modules.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.config_split.php
enables the split matching the detected environment, so each environment
imports only its own set:
| Environment | Split |
|---|---|
local | local |
ci | ci |
development, preview | dev |
stage | stage |
production | None |
The template ships empty config/local, config/ci, config/dev, and
config/stage directories but no splits. Create a split with the matching
machine name before the override has anything to enable.
Config Update
Configuration Update Manager
provides the revert and update functions that other modules build on.
Provisioning installs only this base config_update module. The reports
and the Drush commands that report, revert, and import configuration
changes come from its config_update_ui submodule. Install that submodule
when you need them.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
No settings override.
Devel
Devel is a suite of development tools for inspecting variables, entities, and the service container while debugging.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.devel.php
excludes it from the exported configuration.
Drupal Helpers
Drupal helpers gives deploy hooks and update scripts static facades for common jobs, such as creating taxonomy trees, menu links, users, and redirects.
- Installed: As a dependency of the
ys_demodemo module, declared inys_demo.info.yml.
Configuration
No settings override.
➡️ See Drupal helpers for the helper facades.
Environment Indicator
Environment Indicator shows a colored banner identifying the current environment to prevent accidental changes on the wrong site.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.environment_indicator.php
names the indicator after the detected environment and colors it per
environment: red for production, yellow for stage, and green for
development and preview. Every other environment, local and ci
included, gets a dark green banner with white text. The override also turns
on the toolbar integration and the favicon marker.
Fast 404
Fast 404 answers requests for missing files without bootstrapping Drupal. Drupal core already returns a lightweight 404 for the same file extensions, but only after a full bootstrap. On a site serving many such requests, Fast 404 saves that bootstrap.
- Installed: Never enabled as a Drupal module. The handler runs from the settings file before the module system exists, so requiring the package is enough.
Configuration
settings.fast_404.php
applies only when the module's code is present, and calls
fast404_preboot() with the following settings:
- A request for a missing file with the
txt,png,gif,jpg,jpeg,css,js,ico,swf,flv,cgi,bat,pl,dll,exe, oraspextension gets the fast 404, unless its path starts with/robotsor/system/files. index.php,rss.xml,cron.php, andxmlrpc.phpare on the URL allowlist, which the module checks before the extensions.- Requests for missing image style derivatives reach Drupal, which
generates each derivative on its first request. Drupal generates a
derivative only for a URL with a valid
itoktoken, so these requests can't generate arbitrary derivatives. - Path checking against the router and the URL aliases is off, because it queries the database before Drupal has connected to it. The redirect check that goes with the path check is off too.
Generated Content
Generated Content generates placeholder content from plugin classes for development and testing. Plugins built on its static helpers produce the same content on every run.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step withGENERATED_CONTENT_CREATE=1, unlessDRUPAL_GENERATED_CONTENT_SKIPset to1installs it without generating.
Configuration
settings.generated_content.php
excludes it from the exported configuration.
➡️ See Generated Content for the plugin system and the demo plugin.
Migrate Plus
Migrate Plus extends the core Migrate API with extra source and process plugins and configuration-entity migrations. The demo migration module uses it against the second database. Ships only when the migration feature is selected. Otherwise, the installer removes the requirement.
- Installed: As a dependency of the
ys_migratedemo migration module.
Configuration
No settings override.
➡️ See Migrations for the second database and the demo migration.
Migrate Tools
Migrate Tools provides Drush
commands and a UI to run, roll back, and monitor migrations. The
MigrateContentDeployStep deploy step in ys_migrate runs its
migrate:import command during provisioning. Ships only when the migration
feature is selected. Otherwise, the installer removes the requirement.
- Installed: As a dependency of the
ys_migratedemo migration module.
Configuration
No settings override.
➡️ See Migrations for the second database and the demo migration.
Navigation Extra Tools
Navigation Extra Tools adds a Tools menu to the core Navigation module, with shortcuts that flush caches, rebuild the theme registry, run cron, and run database updates.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step, which also replaces core'stoolbarwith core'snavigationas the administration interface.
Configuration
No settings override.
Pathauto
Pathauto generates URL aliases for content from configurable patterns.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
No settings override.
Redirect
Redirect manages URL redirects and creates them when content URLs change.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
No settings override.
Redis
Redis integrates Drupal with a
Redis-compatible in-memory store for cache and lock backends. Ships only
when the Redis service is selected. Locally, that service is cache,
which runs Valkey.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.redis.php
points the connection at the cache service, makes Redis the default cache
backend, registers the module's container YAML files, and swaps the
bootstrap container over. Nothing applies until the module's code is on
disk and DRUPAL_REDIS_ENABLED is set to 1. The override looks for the
web/modules/contrib/redis directory, so the module doesn't need to be
installed yet. The variable lets a 2-stage deployment provision the service
before switching the cache, and the shipped .env file sets it to 1.
The cache backend, the container YAML files, and the bootstrap container
switch also need the redis PHP extension, or
VORTEX_REDIS_EXTENSION_LOADED set to 1 in its place. Without either,
the override sets only the connection. It reads the following variables:
| Variable | Purpose |
|---|---|
DRUPAL_REDIS_ENABLED | Applies the override when set to 1 and the module's code is on disk |
REDIS_HOST, REDIS_SERVICE_PORT | Connection host and port, cache:6379 by default |
VORTEX_REDIS_EXTENSION_LOADED | When set to 1, applies the cache backend, the container YAML files, and the bootstrap container switch without the redis PHP extension |
Reroute Email
Reroute Email intercepts outgoing emails and redirects them to a configurable address instead of the intended recipients. You can then test email features in non-production environments without delivering mail to real users.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.reroute_email.php
excludes the module from the exported configuration and enables rerouting in
every environment except local, ci, and production.
Rerouting replaces the recipient of an outgoing message with the configured
address, unless that recipient matches DRUPAL_REROUTE_EMAIL_ALLOWED. With
rerouting disabled, every message reaches its intended recipient. Rerouting
is therefore disabled only where that delivery is either wanted or already
intercepted by other means.
The following table shows where rerouting is on, and why:
| Environment | Rerouting enabled | Reason |
|---|---|---|
| Local | No | Pygmy already catches outgoing mail |
| CI | No | The mail collector stores messages instead of sending them |
| Development | Yes | Prevents accidental delivery to real users |
| Preview | Yes | Prevents accidental delivery to real users |
| Stage | Yes | Stage runs a copy of production content, so any address that survives database sanitization is a real one |
| Production | No | Production emails must reach actual recipients |
Rerouting is the fall-through default, so it's also enabled in any custom
environment type set through ENVIRONMENT_TYPE.
Rerouting is off in ci so that tests can assert on the address a message
was sent to. With rerouting on, every message would carry the rerouting
address instead of the intended one.
A site that deselects this module during
installation still sends no mail from ci,
because the mail collector stores messages there regardless. That site does
send mail to real recipients in development, preview, stage, and
custom environments.
The override reads the following variables:
| Variable | Default | Purpose |
|---|---|---|
DRUPAL_REROUTE_EMAIL_ADDRESS | webmaster@your-site-domain.example | Address to receive all rerouted emails |
DRUPAL_REROUTE_EMAIL_ALLOWED | *@your-site-domain.example | Pattern for addresses allowed to bypass rerouting |
To disable email rerouting in an environment where it would otherwise be
enabled, set DRUPAL_REROUTE_EMAIL_DISABLED to 1 there. This is the
supported way for a stage environment to send real mail during user
acceptance testing.
Example settings.reroute_email.php
<?php
/**
* @file
* Reroute email settings.
*/
declare(strict_types=1);
use DrevOps\EnvironmentDetector\Environment;
$settings['config_exclude_modules'][] = 'reroute_email';
// Default reroute email address and allowed list.
$config['reroute_email.settings']['address'] = getenv('DRUPAL_REROUTE_EMAIL_ADDRESS') ?: 'webmaster@your-site-domain.example';
$config['reroute_email.settings']['allowed'] = getenv('DRUPAL_REROUTE_EMAIL_ALLOWED') ?: '*@your-site-domain.example';
if (in_array($settings['environment'], [
Environment::LOCAL,
Environment::CI,
Environment::PRODUCTION,
])) {
// Deliver every message to its intended recipient. Local and CI capture
// outgoing mail by other means, and production sends to real recipients.
$config['reroute_email.settings']['enable'] = FALSE;
}
else {
// Send every outgoing message to the address above instead of to its
// intended recipient, unless that recipient matches the allowed list.
$config['reroute_email.settings']['enable'] = TRUE;
}
// Allow an environment to opt out of the rerouting set above.
if (getenv('DRUPAL_REROUTE_EMAIL_DISABLED') === '1') {
// Deliver every message to its intended recipient.
$config['reroute_email.settings']['enable'] = FALSE;
}
RobotsTxt
RobotsTxt serves robots.txt
from Drupal and lets you edit it in the administration UI, which helps when
the file can't live on disk, for example in multisite setups. Vortex
keeps core's static robots.txt out of the webroot through the
drupal-scaffold file mapping in composer.json, so the module answers
every request for it.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.robotstxt.php
serves a Disallow: / file outside production, so non-production
environments aren't indexed.
SDC Devel
SDC Devel provides development and validation tooling for Single Directory Components (SDC), reporting issues in component definitions and templates.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.sdc_devel.php
excludes it from the exported configuration.
Search API
Search API provides a framework for building search experiences with pluggable indexing backends. It stays required in every project.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step, together with Search API Solr, when the Solr service is selected. Theys_searchmodule depends on it too. Without Solr, nothing installs it.
Configuration
No settings override.
Search API Solr
Search API Solr is a Search API backend that integrates Apache Solr. Ships only when the Solr service is selected.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step, and as a dependency of theys_searchmodule.
Configuration
No settings override.
Security Kit
Security Kit adds configurable security-hardening HTTP headers, including Content Security Policy and anti-framing protection.
- Installed: Required only, not installed during provisioning. Enable it when the project needs it.
Configuration
settings.seckit.php
disables the Content Security Policy and the upgrade-insecure-requests
header locally and in CI, where the site isn't served over HTTPS.
Shield
Shield restricts access to your site by requiring HTTP authentication credentials.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.shield.php
forces Shield on in non-production environments other than local and ci,
where it's forced off. Production is left untouched, so Shield stays under
UI control there.
The following table shows where Shield is on, and why:
| Environment | Shield enabled | Reason |
|---|---|---|
| Local | No | No need for HTTP auth during local development |
| CI | No | Automated tests must access the site freely |
| Development | Yes | Protects development environments from crawlers |
| Preview | Yes | Protects preview environments from crawlers |
| Stage | Yes | Protects staging environments from public access |
| Production | Not enforced | Left to the site configuration: enable or disable it through the UI |
The override reads the following variables:
| Variable | Default | Purpose |
|---|---|---|
DRUPAL_SHIELD_USER | None | HTTP authentication username, applied only when DRUPAL_SHIELD_PASS is set too |
DRUPAL_SHIELD_PASS | None | HTTP authentication password, applied only when DRUPAL_SHIELD_USER is set too |
DRUPAL_SHIELD_PRINT | Restricted access., set in .env | Message shown in the authentication prompt. The module's own default applies when unset |
DRUPAL_SHIELD_ALLOW_ACME_CHALLENGE | None | Set to 1 to keep the /.well-known/acme-challenge/* path open for Let's Encrypt certificate generation |
Shield stays on in development, preview, and stage even when the
credentials are missing. Set DRUPAL_SHIELD_USER and DRUPAL_SHIELD_PASS
in those environments, or the prompt accepts only the credentials stored in
the site's configuration, if there are any.
To disable Shield in an environment where it would otherwise be enabled,
set DRUPAL_SHIELD_DISABLED to 1 there. This is useful for temporary
access during debugging or when an environment doesn't require protection.
Example settings.shield.php
<?php
/**
* @file
* Shield settings.
*/
declare(strict_types=1);
use DrevOps\EnvironmentDetector\Environment;
// Default Shield credentials.
//
// Shield can be enabled and disabled in production through UI.
//
// For other environments, Shield is enforced to be enabled.
// 'DRUPAL_SHIELD_USER' and 'DRUPAL_SHIELD_PASS' environment variables must
// be added in the environment or there will be no way to bypass HTTP Auth.
//
// Note that this approach is a bit different from the other settings, where
// we enable and disable features based on the presence of environment
// variables: we must not disable Shield even if the environment variables
// are not present.
//
// Enforce Shield in all non-prod environments.
if ($settings['environment'] !== Environment::PRODUCTION) {
$config['shield.settings']['shield_enable'] = TRUE;
// But bypass Shield for CI and local environments.
if ($settings['environment'] === Environment::CI || $settings['environment'] === Environment::LOCAL) {
$config['shield.settings']['shield_enable'] = FALSE;
}
}
// Set credentials, but only if the environment variables are present.
$shield_user = getenv('DRUPAL_SHIELD_USER');
$shield_pass = getenv('DRUPAL_SHIELD_PASS');
if (!empty($shield_user) && !empty($shield_pass)) {
$config['shield.settings']['credentials']['shield']['user'] = $shield_user;
$config['shield.settings']['credentials']['shield']['pass'] = $shield_pass;
}
// Allow to override the title of the shield pop-up.
$shield_print = getenv('DRUPAL_SHIELD_PRINT');
if (!empty($shield_print)) {
$config['shield.settings']['print'] = $shield_print;
}
// Allow to disable Shield completely in the environment.
if (getenv('DRUPAL_SHIELD_DISABLED') === '1') {
$config['shield.settings']['shield_enable'] = FALSE;
}
// Allow ACME challenge path for Let's Encrypt certificate generation.
if (getenv('DRUPAL_SHIELD_ALLOW_ACME_CHALLENGE') === '1') {
$config['shield.settings']['method'] = 0;
$shield_acme_path = '/.well-known/acme-challenge/*';
$shield_existing_paths = $config['shield.settings']['paths'] ?? '';
$config['shield.settings']['paths'] = str_contains($shield_existing_paths, $shield_acme_path) ? $shield_existing_paths : trim($shield_existing_paths . "\n" . $shield_acme_path);
}
Stage File Proxy
Stage File Proxy fetches media files from a remote site on demand, so local environments don't need a full copy of the files directory.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.stage_file_proxy.php
sets the origin from DRUPAL_STAGE_FILE_PROXY_ORIGIN outside production.
The shipped .env file sets it to https://www.your-site-domain.example.
When DRUPAL_SHIELD_USER and DRUPAL_SHIELD_PASS are both set, the
override adds them to an https:// origin URL, so a shielded origin still
serves files. It also turns off redirects to the origin, so the module
downloads each requested file and keeps a local copy.
Storybook
Storybook renders the custom theme's component stories through Drupal, so the component library shows the markup the site produces. Ships only when Storybook is selected during installation, which requires a custom theme.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step, which also turns on Twig development mode in thelocalenvironment.
Later in the same deployment, the BuildStorybookDeployStep deploy step
builds the static component library in the local, ci, and
development environments. Set DRUPAL_STORYBOOK_SKIP to 1 to skip
that build.
Configuration
settings.storybook.php
excludes it from the exported configuration. In the local, ci, and
development environments, it also loads services.storybook.yml, which
turns on the module's development mode and lets the Storybook development
server on localhost fetch story renders.
➡️ See Storybook for the component library and its commands.
Testmode
Testmode filters the listings in
registered views during automated tests, so a test sees only content with
a test title prefix such as [TEST].
- Installed: As a dependency of the
ys_demodemo module, declared inys_demo.info.yml.
Configuration
settings.testmode.php
excludes it from the exported configuration.
➡️ See Testmode for the configuration and the Behat integration.
XML Sitemap
XML sitemap generates a multilingual XML sitemap to help search engines index the site.
- Installed: By the
EnableDevelopmentModulesDeployStepdeploy step.
Configuration
settings.xmlsitemap.php
stops cron regeneration and search engine submission outside production, so
non-production environments are never advertised.