Deploying the latest changes to your site can take many forms. Whether you copy files via FTP 😱, manually pull changes via git, or have an automated deployment infrastructure, every process involves a similar set of steps that are often executed via
Standardizing these steps with a version controlled script is a great way to add consistency and repeatability to the deployment process. Then the questions become, what are the steps, what order should they be executed in, when are some steps excluded, and why does this order matter?
Our examples assume a shell-based deployment script, but the same methodology applies whether you define your commands in yml, bash, or any other tool.
This setup is not strictly needed, but it simplifies the commands later in the process and removes the risk of trying to execute commands from the wrong directory. The example below assumes the use of Composer and the execution of a Composer-installed version of
# Define the path to the application. WEB_DIR=/path/to/docroot/folder # Store the path to the drush and drupal commands. DRUSH="$WEB_DIR/../vendor/bin/drush" DRUPAL="$WEB_DIR/../vendor/bin/drupal"
Many of the following examples could be replaced with their
drupal command counterpart, but we will be using
drush commands for consistency.
Display Site Status
We begin by displaying the site status to aid in any subsequent debugging.
# Output information about to site to aid in # debugging failed deployments. "$DRUSH" --root="$WEB_DIR" status
Enable Maintenance Mode
Before any other steps are taken we put the site into maintenance mode to restrict database activity.
# Put the site into maintenance mode to prevent conflicts # from occurring during database updates. “$DRUSH” --root="$WEB_DIR" sset system.maintenance_mode 1
Clear Drush Cache
This isn’t strictly necessary, but sometimes deployments will leverage newly defined
drush commands. If they do, this ensures that they are registered.
# Clear drush cache. "$DRUSH" --root="$WEB_DIR" cc drush
It is important to clear caches before importing configuration to ensure that the correct config settings are active if you’re using
config_filter or a module that implements a
config_filter plugin (e.g.
# Rebuild caches. "$DRUSH" --root="$WEB_DIR" cr
Now we can import the latest configuration. It is important to note that we need to do this before we run any database updates (
drush updb) to ensure the following:
- Staged configuration changes are added to allow database updates to act upon content related to new configuration.
- Ensure update hooks that alter configuration are not overwritten by a configuration import. Note that this scenario will still cause problems on subsequent deploys if configuration is not in version control, but it is a “safer” method if it is forgotten the first time.
# Import the latest configuration. "$DRUSH" --root="$WEB_DIR" config-import -y
Update the Database
Running update hooks after configuration import ensures we can programmatically make changes to entity content and alter custom database schema.
Note that in Drupal 8 we should not be uninstalling/installing modules as was common in Drupal 7, this is now managed via the
# Process any hook_update_N functions and apply # database schema updates. "$DRUSH" --root="$WEB_DIR" updatedb -y
Update Entity Definitions In Drupal 8, running entity updates allows for schema definition changes in the entity base tables to be updated. Running entity updates after database updates ensure that if a module alters entity tables via an update hook, the entity updates system will safely exit after discovering the schema change already exists on the table.
Note that while this is a valuable tool early in the development process, it should not be included in your final deployment script used on a production site due to possible data loss and its inability to update fields with existing data. Additional information on this can be found in this StackExchange thead.
Update: This command was removed from core in 8.7.0 as it was deemed "to be dangerous because it can lead to unforeseen side effects and critical bugs." However, the functionality will live on via the devel_entity_updates module if you want to leverage it for development purposes.
# Update entity definitions. "$DRUSH" --root="$WEB_DIR" entity:updates -y
If you absolutely need to trigger cron as a part of your deployment process it would likely be executed here. However, we would strongly recommend decoupling your cron runs from deployments to avoid extended deployments due to long running cron processes.
# Run cron. "$DRUSH" --root="$WEB_DIR" cron
The Ultimate Cron module will greatly aid in fine tuning your cron execution times and avoid triggering long-running queue processing during a deployment.
Many of the commands above clear caches, but there always seems to be an edge case that requires an additional cache clear. This final cache clear covers those cases.
# Rebuild caches. "$DRUSH" --root="$WEB_DIR" cr
Disable Maintenance Mode
Everything should be ready to go, so we can disable maintenance mode and get the site back online.
# Disable maintenance mode. “$DRUSH” --root="$WEB_DIR" sset system.maintenance_mode 0
Deploying Your Deployment
To standardize this process across the sites we manage, we have created an Ansible role that can be configured with a succinct playbook stored in the site’s repository. By centralizing the deployment process, we can make necessary changes in one place, version it, and roll it out to all of our sites with a one-line change to that site’s deployment playbook.
Note that these are recommended deployment steps for a “regular” server stack. If you are using a cloud hosting provider you should always use the deployment instructions in their documentation.
You can now deploy with greater confidence and an improved understanding of the various actions required to deploy a Drupal site. Along with the knowledge of the proper order to execute them. There will invariably be fresh deployment challenges around the corner, and with a solid grasp of the what, and also the why, you are now better equipped to solve any challenges that come your way.