Settings
Drupal reads its site configuration from settings.php and services.yml:
database connections, file paths and every setting that differs between
environments. Vortex ships its own
versions of
settings.php
and
services.yml,
and the same files work in every environment.
The shipped settings.php detects where the site runs, such as locally, in
CI or on a hosting platform, and applies settings to match. Each module's
overrides live in a small file of their own, so 1 file shows what a module
does differently in each environment.
Drupal Scaffold's own
default.settings.php
and
default.services.yml
are there too, if you'd rather start from those.
This page is for developers who need a setting to differ between
environments, and for the lead or DevOps engineer who brings a project onto
a hosting platform. It explains how settings.php detects the environment
and which variables it reads. It also shows how to add your own per-module
overrides and test them. For the full list of variables, see
Variables.
Approachβ
A site rarely runs the same way everywhere. Local, CI, development, staging and production environments each need their own adjustments: a module on in 1 environment and off in another, or different performance settings, APIs and connected services.
Drupal has no standard way to manage these differences. Its configuration system has no conditional logic, so it can't apply settings per runtime environment or read values from environment variables.
Modules such as config_split keep a separate configuration set per
environment, but they have the following limits:
- Their configuration YAML files can't hold conditions based on the environment.
- They can't read environment variables directly.
- They can't apply dynamic logic, such as setting values based on external service URLs.
Vortex still ships config_split, and it's the right tool when
declarative configuration is enough, such as enabling a module in staging
but not in production. It falls short when settings need conditional logic
or values from the environment. It also can't test automatically which
settings apply in a given environment.
So Vortex splits the job in 2:
settings.phpdetects the environment type from the environment the site runs in. This step applies only the hosting platform's own settings.- Per-module override files hold the configuration overrides, with conditions based on the detected environment type.
The split pays off in 4 ways:
- Environment detection stays separate from configuration logic.
- 1 file shows how a module behaves in each environment.
- When a module goes, you delete its override file and leave
settings.phpalone. - Environment-specific settings stay out of unrelated parts of the configuration.
In practiceβ
Say the business asks you to let an external stakeholder review the stage
environment, which Shield protects
with HTTP authentication. The shipped settings.shield.php
override reads the DRUPAL_SHIELD_DISABLED variable, so you make the change
in your hosting provider's settings:
- In your hosting provider's environment variables, set
DRUPAL_SHIELD_DISABLED=1on thestageenvironment. - Apply the variable. Acquia restarts the environment on its own, and
Lagoon needs a redeployment. The
stagesite then opens without the HTTP authentication prompt.
When the review is over, remove the variable and apply the change the same
way. Confirm that the stage site asks for the Shield credentials again.
You commit nothing, and no other environment changes, because the override file defines the behavior once and each environment opts in through its own variables.
Settings file structureβ
The
settings.php
file has the following sections:
The sections run in a fixed order and load more files from the includes/
directories along the way:
π Drupal bootstrap
β
βΌ
π web/sites/default/settings.php
β
β π’οΈ Database
β Connection credentials from environment variables.
βΌ
β‘ βοΈ General
β File paths, hash salt, timezone, maintenance theme.
βΌ
β’ π Environment type detection
β Loads web/sites/default/includes/providers/settings.<provider>.php
β (acquia, lagoon, circleci, gha, container) and stores the detected
β type in $settings['environment']. Provider files also apply their
β platform settings; no module overrides are applied here.
βΌ
β£ π§© Per-module overrides
β Loads every web/sites/default/includes/modules/settings.<module>.php,
β each applying its overrides based on the detected environment type.
βΌ
β€ π Local overrides
β Loads web/sites/default/settings.local.php and services.local.yml
β when present (local development only).
βΌ
π Fully configured site
Projects with the migration feature load 1 more file between the per-module
overrides and the local overrides: settings.migration.php, which defines
the migration database connection.
Expand to see settings.php
<?php
/**
* @file
* Drupal site-specific configuration file.
*
* Copy `example.settings.local.php` and `example.services.local.yml` to
* `settings.local.php` and `services.local.yml` respectively to
* enable local overrides.
*
* Itβs recommended to leave this file unchanged and manage configuration
* through environment variables and module-specific settings files instead.
* This allows for better portability and easier management of settings across
* environments.
* @see https://www.vortextemplate.com/docs/development/settings
*
* phpcs:disable Drupal.Commenting.InlineComment.NoSpaceBefore
* phpcs:disable Drupal.Commenting.InlineComment.SpacingAfter
* phpcs:disable DrupalPractice.Commenting.CommentEmptyLine.SpacingAfter
* phpcs:disable DrupalPractice.CodeAnalysis.VariableAnalysis.UnusedVariable
*/
declare(strict_types=1);
////////////////////////////////////////////////////////////////////////////////
/// DATABASE ///
////////////////////////////////////////////////////////////////////////////////
// @see https://www.vortextemplate.com/docs/development/settings#database
$databases = [
'default' =>
[
'default' =>
[
'database' => (getenv('DATABASE_NAME') ?: getenv('DATABASE_DATABASE') ?: getenv('MARIADB_DATABASE')) ?: 'drupal',
'username' => (getenv('DATABASE_USERNAME') ?: getenv('MARIADB_USERNAME')) ?: 'drupal',
'password' => (getenv('DATABASE_PASSWORD') ?: getenv('MARIADB_PASSWORD')) ?: 'drupal',
'host' => (getenv('DATABASE_HOST') ?: getenv('MARIADB_HOST')) ?: 'localhost',
'port' => (getenv('DATABASE_PORT') ?: getenv('MARIADB_PORT')) ?: '3306',
'charset' => (getenv('DATABASE_CHARSET') ?: getenv('MARIADB_CHARSET') ?: getenv('MYSQL_CHARSET')) ?: 'utf8mb4',
'collation' => (getenv('DATABASE_COLLATION') ?: getenv('MARIADB_COLLATION') ?: getenv('MYSQL_COLLATION')) ?: 'utf8mb4_general_ci',
'prefix' => '',
'driver' => 'mysql',
],
],
];
////////////////////////////////////////////////////////////////////////////////
/// GENERAL ///
////////////////////////////////////////////////////////////////////////////////
// @see https://www.vortextemplate.com/docs/development/settings#general
$app_root ??= DRUPAL_ROOT;
$site_path ??= 'sites/default';
// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$contrib_path = $app_root . '/' . (is_dir($app_root . '/modules/contrib') ? 'modules/contrib' : 'modules');
// Public files directory relative to the Drupal root.
$settings['file_public_path'] = getenv('DRUPAL_PUBLIC_FILES') ?: 'sites/default/files';
// Private files directory relative to the Drupal root.
$settings['file_private_path'] = getenv('DRUPAL_PRIVATE_FILES') ?: 'sites/default/files/private';
// Temporary file directory.
$settings['file_temp_path'] = (getenv('DRUPAL_TEMPORARY_FILES') ?: getenv('TMP')) ?: '/tmp';
// Location of the site configuration files relative to the Drupal root.
$settings['config_sync_directory'] = getenv('DRUPAL_CONFIG_PATH') ?: '../config/default';
// Load services definition file.
$settings['container_yamls'][] = $app_root . '/' . $site_path . '/services.yml';
// Use DRUPAL_HASH_SALT or the database host name for salt.
$settings['hash_salt'] = getenv('DRUPAL_HASH_SALT') ?: hash('sha256', $databases['default']['default']['host']);
// Timezone settings.
ini_set('date.timezone', (getenv('DRUPAL_TIMEZONE') ?: getenv('TZ')) ?: 'UTC');
date_default_timezone_set((getenv('DRUPAL_TIMEZONE') ?: getenv('TZ')) ?: 'UTC');
// Maintenance theme.
$settings['maintenance_theme'] = (getenv('DRUPAL_MAINTENANCE_THEME') ?: getenv('DRUPAL_THEME')) ?: 'claro';
// Trusted Host Patterns.
// See https://www.drupal.org/node/2410395 for more information on how to
// populate this array.
// Settings for specific environments (including a local container-based
// environment) are populated within provider-specific
// `includes/providers/settings.<provider>.php` files.
// @see https://www.vortextemplate.com/docs/development/settings#environment-type-detection
$settings['trusted_host_patterns'] = [
'^localhost$',
];
// Modules excluded from config export.
// Populate this array in the `includes/modules/settings.<module>.php` file.
$settings['config_exclude_modules'] = [];
// The default list of directories that will be ignored by Drupal's file API.
$settings['file_scan_ignore_directories'] = [
'node_modules',
'bower_components',
];
// Do not automatically create an Apache HTTP .htaccess file in writable
// directories. Overridden in hosting provider settings files as needed.
$settings['auto_create_htaccess'] = FALSE;
// The default number of entities to update in a batch process.
$settings['entity_update_batch_size'] = 50;
////////////////////////////////////////////////////////////////////////////////
/// ENVIRONMENT TYPE DETECTION ///
////////////////////////////////////////////////////////////////////////////////
// @see https://www.vortextemplate.com/docs/development/settings#environment-type-detection
// Use these constants anywhere in code to alter behavior for a specific
// environment.
// @codeCoverageIgnoreStart
if (!defined('ENVIRONMENT_LOCAL')) {
define('ENVIRONMENT_LOCAL', 'local');
}
if (!defined('ENVIRONMENT_CI')) {
define('ENVIRONMENT_CI', 'ci');
}
if (!defined('ENVIRONMENT_DEV')) {
define('ENVIRONMENT_DEV', 'dev');
}
if (!defined('ENVIRONMENT_STAGE')) {
define('ENVIRONMENT_STAGE', 'stage');
}
if (!defined('ENVIRONMENT_PROD')) {
define('ENVIRONMENT_PROD', 'prod');
}
// @codeCoverageIgnoreEnd
// Default environment type is 'local'.
$settings['environment'] = ENVIRONMENT_LOCAL;
// Load provider-specific environment detection settings.
if (file_exists($app_root . '/' . $site_path . '/includes/providers')) {
$files = glob($app_root . '/' . $site_path . '/includes/providers/settings.*.php');
if ($files) {
foreach ($files as $file) {
require $file;
}
}
}
// Allow overriding the environment type using the ENVIRONMENT_TYPE variable.
$environment_type = getenv('ENVIRONMENT_TYPE');
if (!empty($environment_type)) {
$settings['environment'] = $environment_type;
}
////////////////////////////////////////////////////////////////////////////////
/// PER-MODULE OVERRIDES ///
////////////////////////////////////////////////////////////////////////////////
// @see https://www.vortextemplate.com/docs/development/settings#per-module-overrides
if (file_exists($app_root . '/' . $site_path . '/includes/modules')) {
$files = glob($app_root . '/' . $site_path . '/includes/modules/settings.*.php');
if ($files) {
foreach ($files as $file) {
require $file;
}
}
}
// phpcs:ignore #;< MIGRATION
////////////////////////////////////////////////////////////////////////////////
/// MIGRATION SETTINGS ///
////////////////////////////////////////////////////////////////////////////////
// @todo Migration. Remove when migration configuration is no longer required.
if (file_exists($app_root . '/' . $site_path . '/settings.migration.php')) {
require $app_root . '/' . $site_path . '/settings.migration.php';
}
// phpcs:ignore #;> MIGRATION
////////////////////////////////////////////////////////////////////////////////
/// LOCAL OVERRIDE ///
////////////////////////////////////////////////////////////////////////////////
// @see https://www.vortextemplate.com/docs/development/settings#local-overrides
// Load local override configuration, if available.
//
// Copy `example.settings.local.php` and `example.services.local.yml` to
// `settings.local.php` and `services.local.yml` respectively to enable local
// overrides.
//
// `services.local.yml` is loaded from within `settings.local.php`.
//
// Keep this code block at the end of this file to take full effect.
// @codeCoverageIgnoreStart
if (file_exists($app_root . '/' . $site_path . '/settings.local.php') && getenv('DRUPAL_SETTINGS_LOCAL_SKIP') !== '1') {
require $app_root . '/' . $site_path . '/settings.local.php';
}
// @codeCoverageIgnoreEnd
Databaseβ
The database connection comes from environment variables, with a default for each value. Hosting providers and container images name these variables differently, so each setting accepts several names and uses the first one that's set:
| Variable | Alternative variables | Default | Purpose |
|---|---|---|---|
DATABASE_NAME | DATABASE_DATABASE, MARIADB_DATABASE | drupal | Database name |
DATABASE_USERNAME | MARIADB_USERNAME | drupal | Database username |
DATABASE_PASSWORD | MARIADB_PASSWORD | drupal | Database password |
DATABASE_HOST | MARIADB_HOST | localhost | Database host |
DATABASE_PORT | MARIADB_PORT | 3306 | Database port |
DATABASE_CHARSET | MARIADB_CHARSET, MYSQL_CHARSET | utf8mb4 | Character set |
DATABASE_COLLATION | MARIADB_COLLATION, MYSQL_COLLATION | utf8mb4_general_ci | Collation |
The table prefix is always empty, and the driver is always mysql.
The local stack sets these variables in docker-compose.yml. The
alternative names cover providers and images that use names of their own.
For a custom database setup, or a hosting provider that needs specific
values, set the variables in that environment.
Generalβ
This section sets the values every environment needs, and it doesn't depend on the environment type. The provider files in the next section adjust a few of these values for their platform, such as the temporary directory on Acquia.
The following environment variables customize this section:
| Variable | Alternative variables | Default | Purpose |
|---|---|---|---|
DRUPAL_CONFIG_PATH | None | ../config/default | Location of configuration sync directory |
DRUPAL_PUBLIC_FILES | None | sites/default/files | Public files directory path |
DRUPAL_PRIVATE_FILES | None | sites/default/files/private | Private files directory path |
DRUPAL_TEMPORARY_FILES | TMP | /tmp | Temporary files directory path |
DRUPAL_HASH_SALT | None | SHA-256 hash of the database host | Cryptographic salt for security |
DRUPAL_TIMEZONE | TZ | UTC | Runtime timezone |
DRUPAL_MAINTENANCE_THEME | DRUPAL_THEME | claro | Theme used during maintenance mode |
This section also does the following, and no variable changes it:
- Loads
services.ymlas a service container definition - Trusts the
^localhost$host pattern - Skips the
node_modulesandbower_componentsdirectories in file scans - Sets
auto_create_htaccesstoFALSE, so Drupal creates no.htaccessfiles in writable directories.settings.acquia.phpturns it back on for Acquia. - Updates entities in batches of 50
- Starts an empty
config_exclude_moduleslist for the per-module files to fill
The settings.system.php per-module override sets
the page cache lifetime through its DRUPAL_CACHE_PAGE_MAX_AGE variable,
which defaults to 900 seconds. The Variables reference
lists every DRUPAL_* variable.
Hash saltβ
The DRUPAL_HASH_SALT variable sets Drupal's hash_salt, which secures
one-time login links, password-reset URLs and CSRF and form tokens.
When DRUPAL_HASH_SALT isn't set, Vortex derives a fallback salt by
hashing the database host name. A new project then runs without any setup.
The fallback suits local and CI use only, for 2 reasons:
- A database host isn't a secret. It appears in logs, backups,
.envfiles anddrush statusoutput, so the derived value only resists blind guessing. - The derived value changes when the database host changes, for example after a failover or a migration, silently invalidating outstanding one-time login and password-reset links.
Set a unique, long, random DRUPAL_HASH_SALT for every hosted environment
(dev, stage and production) as a platform variable or secret.
settings.lagoon.php sets no salt of its own. On Acquia,
settings.acquia.php loads the platform's settings file after this
section, so a salt set in that file takes precedence. See
Set up hosting for each platform's
steps.
Environment type detectionβ
The environment type names the context the Drupal site runs in: local, CI, development, staging or production. Settings and scripts check it to decide how to behave.
Vortex detects the type from variables that known hosting provider and CI platforms set. The provider files that detect the type also apply their platform's own settings, but they leave module configuration to the per-module override files.
The detected type goes into $settings['environment'], where modules,
settings overrides and shell scripts read it to drive environment-specific
behavior.
Environment type constantsβ
Vortex defines a constant for each supported environment type, listed here with its string value:
ENVIRONMENT_LOCAL(local)ENVIRONMENT_CI(ci)ENVIRONMENT_DEV(dev)ENVIRONMENT_STAGE(stage)ENVIRONMENT_PROD(prod)
Settings files compare $settings['environment'] against these constants.
Shell scripts compare it against the string values.
Detection mechanismβ
The detection logic lives in the includes/providers directory, 1 file per
provider. Each file acts only when its platform's variable is present:
settings.acquia.php:AH_SITE_ENVIRONMENTsettings.circleci.phpandsettings.gha.php:CIsettings.container.php:LOCALDEV_URLsettings.lagoon.php:LAGOON_KUBERNETES
settings.php loads every settings.*.php file in that directory, in
alphabetical order. To support a custom platform, create a
settings.[provider].php file in that directory with its detection logic.
The type starts as ENVIRONMENT_LOCAL, and the provider files change it:
- A hosting provider sets
ENVIRONMENT_DEV, and its own conditions raise the type toENVIRONMENT_STAGEorENVIRONMENT_PROD:- On Acquia, an
AH_SITE_ENVIRONMENTofprodbecomesENVIRONMENT_PROD. A value ofstageortestbecomesENVIRONMENT_STAGE. - On Lagoon, a
LAGOON_ENVIRONMENT_TYPEofproductionbecomesENVIRONMENT_PROD. So does aLAGOON_GIT_BRANCHthat exactly matchesVORTEX_LAGOON_PRODUCTION_BRANCH, which.envsets tomain. When that variable is empty, the script skips this match. Any othermain,master,release/*orhotfix/*branch becomesENVIRONMENT_STAGE.
- On Acquia, an
settings.circleci.phpandsettings.gha.phpboth check the genericCIvariable, so a provider-specific variable such asCIRCLECIhas no effect. Any non-empty value other than0setsENVIRONMENT_CI.docker-compose.ymlpassesCIfrom the runner into the containers.settings.container.phpsets no type. It adds the local container URLs fromLOCALDEV_URLto the trusted host patterns.- With no provider detected, the type stays
ENVIRONMENT_LOCAL.
Besides the type, the provider files apply only their platform's own settings, such as the following:
- Acquia's settings include and temporary directory
- The reverse proxy and cache prefix on Lagoon
- Trusted host patterns
The per-module override files in includes/modules handle module
configuration, so the setup stays modular and independent of the hosting
platforms.
Override the environment typeβ
To force a specific environment type, set the ENVIRONMENT_TYPE
environment variable. Any value other than an empty string or 0
replaces the detected type, including names outside the 5 constants.
Overriding the type helps in the following cases:
- Testing environment-specific behavior locally
- Working around gaps in the detection logic
- Forcing a known environment type for debugging
For example, to simulate the CI environment locally, add
ENVIRONMENT_TYPE=ci to your .env.local file and run ahoy up.
Per-module overridesβ
This section loads every settings.[module].php file from the
includes/modules directory, in alphabetical order. Each file holds the
configuration overrides for 1 Drupal module, or for 1 concern such as
trusted hosts.
Vortex ships an override file for each contributed module it configures, so you can maintain or remove each file on its own. It also ships 3 files that belong to no contributed module:
settings.automated_cron.phpsets the Automated Cron interval to0in thelocalandcienvironments, so cron doesn't run on page requests there.settings.system.phpsets the page cache lifetime and turns on CSS and JavaScript aggregation inprod. Inlocalandci, it shows all errors and skips file permissions hardening. Inci, it stores outgoing email in the state system instead of sending it.settings.trusted_hosts.phpadds each domain in the comma-separatedDRUPAL_TRUSTED_HOSTSvariable to the trusted host patterns.
β‘οΈ See Contributed modules for what each shipped override configures, module by module.
Create custom module settingsβ
To add settings for a new module, create a file that follows this naming pattern:
web/sites/default/includes/modules/settings.[module_name].php
Each settings file follows these rules:
- Use environment type constants, such as
ENVIRONMENT_LOCALandENVIRONMENT_PROD, for conditional logic. - Use environment variables for configuration values.
- Provide a default value for each environment variable that isn't set.
- Keep the file self-contained, so you can remove it without affecting other modules.
The following override file for the Environment Indicator module follows these rules:
Example settings.environment_indicator.php
<?php
/**
* @file
* Environment indicator settings.
*/
declare(strict_types=1);
$config['environment_indicator.indicator']['name'] = $settings['environment'];
$config['environment_indicator.indicator']['bg_color'] = '#006600';
$config['environment_indicator.indicator']['fg_color'] = '#ffffff';
$config['environment_indicator.settings']['toolbar_integration'] = [TRUE];
$config['environment_indicator.settings']['favicon'] = TRUE;
switch ($settings['environment']) {
case ENVIRONMENT_PROD:
$config['environment_indicator.indicator']['bg_color'] = '#ef5350';
$config['environment_indicator.indicator']['fg_color'] = '#000000';
break;
case ENVIRONMENT_STAGE:
$config['environment_indicator.indicator']['bg_color'] = '#fff176';
$config['environment_indicator.indicator']['fg_color'] = '#000000';
break;
case ENVIRONMENT_DEV:
$config['environment_indicator.indicator']['bg_color'] = '#4caf50';
$config['environment_indicator.indicator']['fg_color'] = '#000000';
break;
}
Local overridesβ
settings.php ends by loading settings.local.php when it exists, so you
can override settings on your machine and leave the shared configuration
alone. To turn the local overrides on, follow these steps in
web/sites/default:
- Copy
example.settings.local.phptosettings.local.php. - Copy
example.services.local.ymltoservices.local.yml.
Git ignores both copies. settings.local.php loads services.local.yml.
Drupal builds a new service container when its list of service files
changes, so no cache rebuild is needed. Confirm that the HTML source of the
next page you load carries Twig debug comments, such as
<!-- THEME DEBUG -->.
The example files change the following settings:
- Every error message shows, with backtrace information.
- CSS and JavaScript aggregation is off.
- The render, page and dynamic page caches are bypassed.
- Twig debugging is on.
- Responses carry cacheability debug headers.
rebuild.phpis accessible.- File permissions hardening is skipped.
To check how the site behaves without the local overrides, set the
DRUPAL_SETTINGS_LOCAL_SKIP environment variable to 1. The site then
skips settings.local.php even when it exists.
Expand to see example.settings.local.php
<?php
/**
* @file
* Local development override configuration feature.
*
* To activate this feature, copy and rename it such that its path plus
* filename is 'sites/default/settings.local.php'. No changes to settings.php
* are required as it automatically loads settings.local.php if present.
*
* If you are using a site name in the path, such as 'sites/example.com', copy
* this file to 'sites/example.com/settings.local.php'.
*
* @see https://git.drupalcode.org/project/drupal/-/blob/11.x/core/assets/scaffold/files/example.settings.local.php
*/
declare(strict_types=1);
/**
* Enable local development services.
*/
$settings['container_yamls'][] = $app_root . '/' . $site_path . '/services.local.yml';
/**
* Show all error messages, with backtrace information.
*
* In case the error level could not be fetched from the database, as for
* example the database connection failed, we rely only on this value.
*/
$config['system.logging']['error_level'] = 'verbose';
/**
* Disable CSS and JS aggregation.
*/
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
/**
* Disable the render cache.
*
* Note: you should test with the render cache enabled, to ensure the correct
* cacheability metadata is present. However, in the early stages of
* development, you may want to disable it.
*
* This setting disables the render cache by using the Null cache back-end
* defined by the development.services.yml file above.
*
* Only use this setting once the site has been installed.
*/
$settings['cache']['bins']['render'] = 'cache.backend.null';
/**
* Disable caching for migrations.
*
* Uncomment the code below to only store migrations in memory and not in the
* database. This makes it easier to develop custom migrations.
*/
# $settings['cache']['bins']['discovery_migration'] = 'cache.backend.memory';
/**
* Disable Internal Page Cache.
*
* Note: you should test with Internal Page Cache enabled, to ensure the correct
* cacheability metadata is present. However, in the early stages of
* development, you may want to disable it.
*
* This setting disables the page cache by using the Null cache back-end
* defined by the development.services.yml file above.
*
* Only use this setting once the site has been installed.
*/
$settings['cache']['bins']['page'] = 'cache.backend.null';
/**
* Disable Dynamic Page Cache.
*
* Note: you should test with Dynamic Page Cache enabled, to ensure the correct
* cacheability metadata is present (and hence the expected behavior). However,
* in the early stages of development, you may want to disable it.
*/
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';
/**
* Allow test modules and themes to be installed.
*
* Drupal ignores test modules and themes by default for performance reasons.
* During development it can be useful to install test extensions for debugging
* purposes.
*/
# $settings['extension_discovery_scan_tests'] = TRUE;
/**
* Enable access to rebuild.php.
*
* This setting can be enabled to allow Drupal's php and database cached
* storage to be cleared via the rebuild.php page. Access to this page can also
* be gained by generating a query string from rebuild_token_calculator.sh and
* using these parameters in a request to rebuild.php.
*/
$settings['rebuild_access'] = TRUE;
/**
* Skip file system permissions hardening.
*
* The system module will periodically check the permissions of your site's
* site directory to ensure that it is not writable by the website user. For
* sites that are managed with a version control system, this can cause problems
* when files in that directory such as settings.php are updated, because the
* user pulling in the changes won't have permissions to modify files in the
* directory.
*/
$settings['skip_permissions_hardening'] = TRUE;
/**
* Hide administration navigation. Useful for theming while logged in as admin.
*/
// $settings['hide_admin_navigation'] = TRUE;
Expand to see example.services.local.yml
# Local development services.
#
# The example.services.local.yml file allows the developer to override
# container parameters for debugging.
#
# To activate this feature, follow the instructions at the top of the
# 'example.settings.local.php' file, which sits next to this file.
#
# Be aware that in Drupal's configuration system, all the files that
# provide container definitions are merged using a shallow merge approach
# within \Drupal\Core\DependencyInjection\YamlFileLoader.
# This means that if you want to override any value of a parameter, the
# whole parameter array needs to be copied from
# sites/default/default.services.yml or from core/core.services.yml file.
#
# @see https://git.drupalcode.org/project/drupal/-/blob/11.x/core/assets/scaffold/files/development.services.yml
parameters:
http.response.debug_cacheability_headers: true
# Enable Twig debugging and caching (auto_reload inherits core default).
twig.config:
debug: true
auto_reload: null
# Twig cache allows Xdebug to work with .twig files.
cache: true
services:
cache.backend.null:
class: Drupal\Core\Cache\NullBackendFactory
logger.channel.config_schema:
parent: logger.channel_base
arguments: [ 'config_schema' ]
config.schema_checker:
class: Drupal\Core\Config\Development\LenientConfigSchemaChecker
arguments:
- '@config.typed'
- '@messenger'
- '@logger.channel.config_schema'
tags:
- { name: event_subscriber }
Guidelinesβ
Follow these guidelines when you work with settings:
-
Don't modify
settings.phpdirectly.
Use environment variables for general settings or per-module override files for any custom or environment-aware configuration. -
Keep all overrides isolated by module.
Each file holds the logic for 1 module only. When the module goes, you delete its override file, and no unrelated setting changes. -
Use environment variables for configuration that changes by environment.
Prefix each such variable withDRUPAL_, for exampleDRUPAL_MY_SETTING, to tell it apart from other environment variables.
Define a hardcoded default value for each environment variable. -
Guard a variable by what it holds.
Read a boolean flag, a variable that only switches behavior on, withgetenv('DRUPAL_MY_FLAG') === '1'. Every other value leaves the behavior off: an unset variable, an empty string,0,trueandyes.
Read a value carrier, a variable whose value is used, with!empty(getenv('DRUPAL_MY_VALUE')). Assign it to a variable first when the value is needed after the guard.
Compare with===and!==, never with==.
1Each of the following flags acts only when it's exactly 1. Any other
value, such as true, yes or on, counts as unset, so the flag has no
effect. Set each flag to exactly 1, wherever you set it:
DRUPAL_CLAMAV_ENABLEDDRUPAL_REDIS_ENABLEDDRUPAL_REROUTE_EMAIL_DISABLEDDRUPAL_SHIELD_DISABLEDDRUPAL_SHIELD_ALLOW_ACME_CHALLENGEDRUPAL_TMP_PATH_IS_SHAREDDRUPAL_SETTINGS_LOCAL_SKIPVORTEX_REDIS_EXTENSION_LOADED
-
Gate on the presence of a contributed module only when the file needs it.
file_exists($contrib_path . '/my_module')belongs in an override file that loads a file from the module directory or registers its paths. An override file that only writes$configor$settingsskips the guard, because Drupal ignores overrides for a module that isn't installed. -
Use conditions based on environment type within per-module override files.
The conditions keep environment-specific configuration out of the mainsettings.phpfile.
Check the current environment type in$settings['environment'].
Test settings with unit testsβ
Vortex includes a set of unit tests that verify the settings for each detected environment type. Maintain them in your project, alongside your settings.
The tests check each environment type and each environment variable that switches behavior on or off. They live in 3 test classes:
DatabaseSettingsTest: the database connection settingsEnvironmentSettingsTest: the settings in every environment typeSwitchableSettingsTest: the settings that environment variables switch on or off
To run only the settings tests, open a shell in the CLI container with
ahoy cli and run the following command:
vendor/bin/phpunit --group=drupal_settings
Confirm that PHPUnit reports OK at the end of the run.
The tests are part of the unit test suite, so ahoy test-unit runs them
too. If you don't want to maintain them, remove them.