Configuring Drupal's Settings Files
After completing a Drupal installation, one of the files we edit most often on a per-project basis is settings.php. The database connection, trusted domains, the configuration directory, and some environment-specific settings can all be managed through this file.
In a standard Composer installation, we usually find the file at:
web/sites/default/settings.phpDrupal also supports a settings.local.php structure so we can use different values in local development or testing environments without changing the main settings.
What Is the settings.php File For?
settings.php is the file that holds Drupal's site-specific settings.
For example, it may contain values such as:
- the database connection,
- trusted host settings,
- the configuration sync directory,
- the hash salt,
- some file system related settings,
- reverse proxy settings
A significant part of this file is prepared automatically during the Drupal installation.
How Is settings.php Created?
Inside Drupal, the example settings file is located at:
web/sites/default/default.settings.phpA settings.php is created from this during installation.
If we need to prepare it manually:
cp web/sites/default/default.settings.php \
web/sites/default/settings.phpcommand can be used.
However, when a normal installation is done through the Drupal Installer, we usually don't need to do this ourselves.
Database Settings
The database information we created in the previous article is saved by Drupal into settings.php.
For example:
$databases['default']['default'] = [
'database' => 'drupal_site',
'username' => 'drupal_user',
'password' => 'GucluBirSifreBuraya',
'host' => 'localhost',
'port' => '3306',
'driver' => 'mysql',
'prefix' => '',
'collation' => 'utf8mb4_general_ci',
];If we go through these values one by one:
database is the name of the database Drupal will use.
username and password are the credentials of the user that will connect to this database.
host specifies the address of the database server.
driver determines which database driver Drupal will use. For MySQL and MariaDB this value is usually mysql. Drupal's current default.settings.php file also defines the basic connection structure this way.
Is localhost Always Correct?
No.
If Drupal and MySQL run on the same server in a classic setup:
'host' => 'localhost',can be correct.
However, in container-based environments like Docker, the database may run in a different container.
For example, if our database service in Docker Compose is:
services:
db:
image: mariadbthen the host value on the Drupal side will usually be:
'host' => 'db',This is because, inside a container, localhost refers to the Drupal container that is currently running.
Should We Add Database Credentials to Git?
This can vary depending on the project structure, but keeping the production database password directly in the Git repository is not a good approach.
For example, the credentials can be taken from environment variables:
$databases['default']['default'] = [
'database' => getenv('DB_NAME'),
'username' => getenv('DB_USER'),
'password' => getenv('DB_PASSWORD'),
'host' => getenv('DB_HOST') ?: 'localhost',
'driver' => 'mysql',
];This way, the same code can be used across different environments while database credentials are kept separately on the server side.
Drupal's security documentation also states that sensitive information can be stored outside the document root or through a suitable secret management method.
The Trusted Host Setting
One of the important settings that needs to be configured in a production environment is the trusted_host_patterns value.
For example, if our site will run from:
example.comand:
www.example.comaddresses, we can define it as:
$settings['trusted_host_patterns'] = [
'^example\.com$',
'^www\.example\.com$',
];These values are written as regular expressions, not plain domains.
For this reason:
.characters are escaped as:
\.The Trusted Host setting protects against certain attacks that can be carried out through the HTTP Host header. If a request comes in through a host that doesn't match the defined pattern, Drupal returns an HTTP 400 response.
If Subdomains Are Used
For example, all of the following addresses might belong to the project:
example.com
www.example.com
test.example.com
stage.example.comInstead of writing each one separately, a suitable regex can be used.
For example:
$settings['trusted_host_patterns'] = [
'^(.*\.)?example\.com$',
];This structure makes example.com match along with its subdomains.
However, the trusted host pattern shouldn't be kept broader than necessary. The goal is to clearly limit which domains are allowed to access the site.
Configuration Sync Directory
If we use Drupal's Configuration Management, we can also define the directory configuration files are exported to inside settings.php.
For example:
$settings['config_sync_directory'] = '../config/sync';In this case, our project structure might look like this:
project/
├── config/
│ └── sync/
├── vendor/
└── web/Here, the config directory stays outside the web root.
When we run a configuration export:
vendor/bin/drush cexthe YAML files are written to this directory.
During import:
vendor/bin/drush cimthe configuration files in the same directory are used.
In Drupal 8.8 and later, the sync directory is defined through $settings['config_sync_directory'].
What Is hash_salt?
Another value we'll encounter inside settings.php is the:
$settings['hash_salt'] = '...';setting itself.
Drupal uses this in one-time login links, form tokens, and similar security-related operations.
During a normal installation, Drupal generates this value automatically.
For this reason, if we're regenerating settings.php while moving an existing site to another server, we need to make sure we don't accidentally lose the old hash_salt value.
If the value changes, some existing one-time links may become invalid. Drupal's documentation also states that if the same site runs on multiple web servers, the hash_salt value needs to be the same on all of them.
Why Use settings.local.php?
It's normal to need different settings in a development environment than in production.
For example, in the local environment we might want to:
- disable cache,
- disable CSS/JS aggregation,
- load development services,
- turn on debug settings
If we write these directly into settings.php, there's a risk of accidentally carrying them over to the production environment.
Instead, we can use:
web/sites/default/settings.local.phpDrupal core also ships a ready example file for this:
web/sites/example.settings.local.phpDrupal offers this structure specifically to override the main settings.php values in development and testing environments.
Creating the settings.local.php File
We can copy the example file:
cp web/sites/example.settings.local.php \
web/sites/default/settings.local.phpHowever, creating the file alone isn't enough.
We need to make sure the local file is included inside settings.php.
There's usually a section like this near the bottom of the file:
if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) {
include $app_root . '/' . $site_path . '/settings.local.php';
}What this code does is simple:
it loads settings.local.php if it exists, and otherwise continues normally.
Drupal's development documentation also recommends loading the local settings file this way.
Disabling CSS and JavaScript Aggregation Locally
While developing, we don't want to keep seeing the old result in the browser even though we've made a change to a CSS or JavaScript file.
For this reason, aggregation can be disabled in the local environment:
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;It makes more sense to keep these settings in settings.local.php rather than settings.php.
In production, having aggregation enabled is generally preferred for performance reasons.
Disabling Cache
While developing a theme or a module, Drupal's cache system can sometimes make it harder to see our changes right away.
Certain cache bins can be disabled during local development.
For example:
$settings['cache']['bins']['render'] = 'cache.backend.null';
$settings['cache']['bins']['page'] = 'cache.backend.null';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';The goal here is to make Drupal use the null cache backend instead of these cache layers.
These settings are useful during development but shouldn't be used in production.
Drupal's official development documentation also shows these settings for the local development scenario.
development.services.yml
Another file we'll often encounter alongside settings.local.php is:
web/sites/development.services.ymlThis file can be loaded from within the local settings:
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml';This file lets us change Drupal's service container settings in the development environment.
For example, the null cache backend can be defined here.
The development.services.yml file that ships in Drupal core is already prepared for local development.
The Twig Debug Topic
In older Drupal projects, it's quite common to see Twig debug settings directly inside development.services.yml.
For example:
parameters:
twig.config:
debug: true
auto_reload: true
cache: falseHowever, we need to pay attention to the Drupal version here.
Drupal's current development documentation states that from Drupal 10.3 onward, Twig development settings can be controlled from the admin interface, and the old method isn't recommended in every case.
For this reason, we shouldn't carry over every development.services.yml setting we see in older projects directly into new ones.
Should settings.local.php Be Added to Git?
In most projects, settings.local.php contains settings specific to the developer's own environment.
For example, one developer might have:
$settings['container_yamls'][] = DRUPAL_ROOT . '/sites/development.services.yml';while another developer might use a different local service.
For this reason:
settings.local.phpis usually not added to Git.
Instead, an example file can be kept:
settings.local.example.phpand each developer can create their own:
settings.local.phpfile.
This way, personal development settings don't get mixed into the repository.
Using Settings Based on Environment
In Drupal projects, using the same settings across development, testing, and production environments isn't always correct.
For example, let's consider:
Local
Test
Productionenvironments.
In the local environment:
Cache: Off
CSS/JS aggregation: Off
Debug: Onmight be the case.
In production, we want:
Cache: On
CSS/JS aggregation: On
Debug: OffThis is exactly where the real advantage of environment-based structures like settings.local.php shows up.
The code stays the same while settings can change depending on the environment it runs in.
Permissions of the settings.php File
During Drupal installation, settings.php may be made writable. However, once installation is complete, it's not recommended to leave the file in a state where it can be unnecessarily modified by the web server.
Drupal's own default.settings.php file specifically states that the file should be protected again after installation.
We can check the file's current permissions with:
ls -l web/sites/default/settings.phpcommand.
For example, an output like:
-r--r----- settings.phpshows that the file's write access has been restricted.
The exact owner and permission values to use should be determined based on the server's Nginx/Apache, PHP-FPM, and deployment user structure.
Being Careful About Storing Passwords in settings.php
The following structure technically works:
'password' => 'my-production-password',but if settings.php is kept in a Git repository, the production password ends up in the repository too.
A better approach is to take the password from outside.
For example:
'password' => getenv('DB_PASSWORD'),and on the server:
DB_PASSWORD="..."can be defined this way.
In more sensitive projects, secret management tools or dedicated files kept outside the document root can be used instead of environment variables.
Don't Forget to Clear the Cache
After making changes to settings.php, settings.local.php, or the service container settings, a cache rebuild may be needed for some changes to take effect.
If we're using Drush, we can run:
vendor/bin/drush crIt's especially important to rebuild the cache if we've made changes to development.services.yml or container settings.
Example settings.php Structure
If we bring the relevant sections together for a simple project, a structure similar to the following can emerge:
$databases['default']['default'] = [
'database' => getenv('DB_NAME'),
'username' => getenv('DB_USER'),
'password' => getenv('DB_PASSWORD'),
'host' => getenv('DB_HOST') ?: 'localhost',
'driver' => 'mysql',
];
$settings['trusted_host_patterns'] = [
'^example\.com$',
'^www\.example\.com$',
];
$settings['config_sync_directory'] = '../config/sync';
if (file_exists($app_root . '/' . $site_path . '/settings.local.php')) {
include $app_root . '/' . $site_path . '/settings.local.php';
}In this example, we take the database credentials from the environment, limit which domains can access the site, move the configuration directory outside the web root, and load local development settings if they exist.
Conclusion
In Drupal, settings.php isn't just a file that holds the database password. Many fundamental settings specific to the site and its runtime environment are managed here.
In production, in particular:
- the database credentials,
trusted_host_patterns,config_sync_directory,hash_salt,- file permissions
should be checked.
In local development, using settings.local.php instead of changing production settings provides a cleaner structure.
Thanks to this separation, we can use the same Drupal codebase across development, testing, and production environments, changing only the settings each environment needs.