One of the struggles that developers face when moving to Drupal 8 is the lack of best practices in deploying Drupal sites. The Challenges in deployment revolve around Dependency Management, Drupal Contrib Modules/Themes, Configuration Management, and of course Code Base.

Drupal 7 has no such problems. But ahhh, Drupal 8 comes with lots of stuff to manage. One of the biggest changes in Drupal 8 is the adoption of Composer. Good things come at a price.

We will use one codebase for one Drupal site and use Git for version control and deployment.


Composer is a dependency manager for PHP (like npm for Node or pip for Python). Drupal core uses Composer to manage core dependencies like Symfony components and Guzzle. Composer allows us to systematically manage a list of dependencies and their subsidiary dependencies. Composer installs these dependencies via a manifest file called composer.json.


This composer.json file contains the dependencies that the project requires. You can install it by running

composer install

for the first time. It locates, downloads, validates, and loads the packages. It also ensures that exactly the right versions for each package are used, and maintains the log file called composer.lock.

Note: always commit your composer.lock file, because it contains the exact version of the dependencies that you have defined in the project.

If you want to update any specific package, it’s a good practice to run this command:

composer update package/package-name

You should never run composer update, because composer will try to update every single dependency. This can cause problems to your site.

Drupal Composer

drupal-composer/drupal-project is the life-saver project for managing your site dependencies with Composer.

To install this project template, run this command:

composer create-project drupal-composer/drupal-project:8.x-dev drupal8 — stability dev — no-interaction

It will automatically install a Drupal site with all the dependencies. It will also install Drupal console and Drush locally.

Composer is one of the fastest ways to install dependencies, as it caches the dependencies and loads data from the cache the next time.

Directory structure


It is different from the Drupal directory structure. You can reassemble web directory with the public directory which contains Drupal files. All third party dependencies are outside the web folder.

You can install any Drupal Modules, themes, and profiles through composer which will be downloaded in the contrib folder inside the modules, themes, and profiles, respectively. In this way, the composer.lock file will have a record of all the Drupal contrib modules along with the third party dependencies.

To download any modules and themes using composer, run the following:

composer require drupal/mediumish_blog
# For installing theme, we will use drupal console
drupal theme:install mediumish_blog


As are all the dependencies and Drupal contrib modules, themes are managed by composer. Therefore, we will not push this content to Git.

# Ignore directories generated by Composer /drush/contrib /vendor/ /web/core/ /web/modules/contrib/ /web/themes/contrib/ /web/profiles/contrib/ /web/libraries/
# Ignore sensitive information /web/sites/*/settings.php /web/sites/*/

Configuration management

Deployment and configuration management are common actions of a project life cycle. We have installed various modules and configured our local site, but our production site has no such configuration.

In Drupal 7, we had the features module, which is used to sync configuration. But Drupal 8 has an inbuilt solution for managing configurations. This allows you to export complete website configurations and store them in YAML files. Exported files can be imported to another website with the same result.

Drupal’s configuration system helps to solve the config files synchronization problem in two ways: a unified way to store configuration, and a process to import/export changes between instances of the same site.

How to synchronize config files

Open /web/sites/default/settings.php and set $config_directories[‘sync’]

$config_directories[‘sync’] = ‘../config/sync’;

It’s a good practice to store config files outside of the web directory to avoid making them accessible from the Internet.

Now use the Drupal console to export the configuration:

drupal config:export
# import on prod server
drupal config:import

Note: the production and local Drupal sites should have same UUIDs. Check here for more info.

Note: Drupal configuration management has a bug — custom blocks data should neither be imported nor be exported. View the Issue Link here.


We will use Git to add, commit, and push the local site’s data with all the configuration. This will be pulled from the prod server/site. Let’s see the flow:

# Local
git add .
git commit -m”Add commit message”
git push origin HEAD
# Server
git pull otigin HEAD
composer install # to install any new dependencies, drupal contrib modules, themes
drupal config:import # to import the configuration
drupal cache:rebuild all # rebuild the cache

Update modules, themes, and profiles

composer update drupal/mediumish_blog
drupal update:execute mediumish_blog
drupal update:execute all

Update Drupal core

Generally, we face problems in updating the Drupal core. But composer has a simple way to manage this, too:

composer update drupal/core — with-dependencies

It will update the Drupal core and all its associated dependencies.

Managing environment configuration

My favorite aspect of Drupal, as a developer, is the ability to manage different environment configurations. This can be done by using the vlucas/phpdotenv module, which also comes with the Drupal composer template.

Anything that is likely to change between deployment environments — such as database credentials or credentials for 3rd party services — should be extracted from the code into environment variables. Basically, an .env file is an easy way to load custom configuration variables that your application needs without having to modify any other files.

Rename .env.example to .env file and add all the credentials as a key-value pair in .env file.

load.environment.php file in the root will load this .env file and make it available for you.

How to use .env file

Open /web/sites/default/setting.php and add this set of code:

$databases[‘default’][‘default’] = [ ‘database’ => getenv(‘MYSQL_DATABASE’), ‘driver’ => ‘mysql’, ‘host’ => getenv(‘MYSQL_HOSTNAME’), ‘namespace’ => ‘Drupal\\Core\\Database\\Driver\\mysql’, ‘password’ => getenv(‘MYSQL_PASSWORD’), ‘port’ => getenv(‘MYSQL_PORT’), ‘prefix’ => ‘’, ‘username’ => getenv(‘MYSQL_USER’), ];

Open .env file and set the following credentials:


Now, as all our credentials are stored in the .env file, we can push our settings.php to the server and manage its configuration through .env file.

We generally enable twig debugging while in development and disable upon production. This can also be done easily and smoothly through an .env file.

Add a new key value pair in .env file:


Now copy web/sites/example.settings.local.php to web/sites/default/settings.local.php and add this code in web/sites/ under parameters:

twig.config: debug: true auto_reload: true cache: false

Now open web/sites/default/settings.php and add this code:

$env = getenv(‘APP_ENV’);
$base_path = $app_root . ‘/’ . $site_path; $settingsFile = $base_path . ‘/settings.’ . $env . ‘.php’;
if (file_exists($settingsFile)) { include $settingsFile; }

So, in this way, if you set your APP_ENV=’local’, Twig debug will be enabled. Upon production, you can disable by setting APP_ENV=’prod’. You can also configure different configurations for different environments.


Drupal 8 offers a built-in solution for exporting and importing site configurations, which is way better than what you could do in D7. Dependencies and contrib modules/themes are managed by the composer itself.

It’s not yet perfect, as there is no standard approach, but the workflow described above is a simple and efficient solution. You can define your own workflow based on your needs.

For reference, I have pushed the code to this repo.

I hope you have found this article useful. I would love to hear your feedback :)

This article is from my own blog. To read more such articles, follow it here.