What order should the following drush commands be ran?

  • config-import
  • updatedb
  • entity-updates

Also, I see entity-updates fail a lot due to field_delete_data* tables existing. How can I delete them as part of my automated deployment?

  • 1
    You shouldn't delete those tables yourself unless you're absolutely sure they are not being referenced. Cron should clean them up. See my question I asked about this recently drupal.stackexchange.com/questions/253055/…
    – Kevin
    Commented Jan 24, 2018 at 16:49
  • The issue is that I cannot wait for cron to do the tidy up, as we do deployments as and when Commented Jan 24, 2018 at 17:15
  • 1
    You should not delete those tables at will - review that question as to the whys.
    – Kevin
    Commented Jan 24, 2018 at 17:16
  • I've not yet encountered an issue in doing so :/ Commented Jan 24, 2018 at 17:17

5 Answers 5


Drush 10.3.0 now provides a deploy command to standardize how Drupal deployment works. This command performs the following:

drush updatedb --no-cache-clear
drush cache:rebuild
drush config:import
drush cache:rebuild
drush deploy:hook

Database updates always come before configuration import! Support for automatic entity updates has been removed from Drupal core (change record) and entup has been removed from Drush core. Whenever an entity type or field storage definition needs to be created, changed or deleted, it has to be done via hook_update_N().

Here is the updated deployment routine I'm happiest with.

drush state:set system.maintenance_mode 1
drush cache:rebuild
git pull
composer install --no-dev
drush deploy
drush state:set system.maintenance_mode 0
drush cache:rebuild

This also means you have to run two releases if you want to uninstall and remove a contrib module. First release to deploy the updated config that disables the module. Second release to deploy the updated composer.json and lock file after you removed it with Composer.

To make real consecutive releases possible you might want to pass the current release's commit SHA1 to the deployment script and then replace git pull with a more exact routine (where $1 is the SHA1):

# If not empty 1st argument passed to the script, do:
if [ -n "$1" ]; then
  git reset --hard "$1"
  git pull

Otherwise the consecutiveness can not be guaranteed when you push two new releases at once or within a short period. As then the first release's triggered git pull will simply pull the latest changes (from the second release), where instead it should pull only the changes included in the first release. See the full sample repo leymannx/drupal-circleci-behat.

Credit for this git snippet goes to CircleCI. This is how they are doing it in their containers.

  • 6
    I'm strongly against using entup in such a workflow. Modules must provide update functions for their entity type changes, entup is not reliable (there are many changes that it can't do and will fail with an exception) and should only be used when developing a not-yet-released entity type. It's something that non-cli users can not execute.
    – Berdir
    Commented Jan 25, 2018 at 19:25
  • 2
    Since the answer mentions composer: It is recommended to run composer install with autoloader optimization options such as --optimize-autoloader. Commented Feb 11, 2018 at 19:42
  • So am I reading this right that you run cache:rebuild 5 times? 2 inside the new drush deploy and 3 outside of that? Commented Aug 26, 2020 at 21:04
  • 2
    I've added a git clean -fd config/sync after the git pull in my deployment scripts. On our small projects, config changes on live are allowed and common, and if live changed a config that needed to be removed by dev later, then that changed config file on live was not deleted by git. The git clean -fd config/sync then removes all left-over config files (where config/sync is the path of your configuarion sync directory).
    – Hudri
    Commented Jun 23, 2021 at 9:29
  • @ElijahLynn You would have to. If you update the maintenance mode setting, you have to rebuild the cache for it to take effect.
    – mbomb007
    Commented Feb 6 at 14:58

The sequence of commands should be:

updatedb (which runs update hooks)

You do not want to run entity-updates because it is deprecated, see https://www.drupal.org/node/3034742. Instead, rely on update hooks (hook_update_N) to properly modify any database schema or necessary configurations.

It is imperative that updatedb is the first command run that boots Drupal after code has been changed. You can see https://www.drupal.org/project/commerce/issues/3100553 for some commentary on what issues might arise when that is not done.

Example Deployment Script

Here is an example deployment script that has had a lot of review and discussion behind it, but consider it a starting point. It's likely there will be adjustments you would want to make. It does assume you're deploying an artifact (notice that composer install is not run on deployment).

drush sset system.maintenance_mode TRUE
# Create a restore point by taking backups of anything that is not in the code repository: database, media, cache
# Checkout the code you are deploying
drush updb
drush cim sync -y || drush cim sync -y
drush cim sync -y
drush sset system.maintenance_mode FALSE
drush cr

You can see https://www.bounteous.com/insights/2020/03/11/automate-drupal-deployments/ for a deeper explanation behind this. See also https://github.com/drush-ops/drush/pull/4359/ which is a PR to include a deploy command in Drush.

I mentioned the script above is a starting point, I've documented some variations that you might want to apply to that script (or any deploy script you use) that might be helpful: https://www.bounteous.com/insights/2020/03/12/automated-drupal-deployment-and-rollback-recipes/


Here is our CI script, quite the same :)

drush cr
git pull
composer install
# drupal console enforce modules are enabled before any config is installed
drupal config:import:single --directory="config/sync" --file="core.extension.yml"
drush cr
drush -y updb
drush cr
drush -y cim
drush cr

the config:import:single was helpfull when diffrent developers where creating modules without requiring the correct dependencies in their .info.yml

  • Ah I think this was the reason why we did run drush cim befor drush updb once. So this looks like a much better solution just in case somone forgets to put the correct dependencies into the info.yml
    – macbert
    Commented Jul 14, 2021 at 8:47

If you need to import custom translations too make sure to run a drush cim afterwards importing as some of the lables are translated in config and some in the po files.

At moment our update job looks like this after a git pull. And make sure if you are on dev to export your changes before pulling with drush cex ;-) :

composer install --no-interaction -d /var/www/html/
drush updatedb -y
drush cr -y
drush cim -y

drush locale:check -y #make sure to switch this to local only in settings.php in production
drush locale:update -y
drush locale:import de ../translations/custom-translations.de.po --type=customized --override=all -y
drush locale:import de ../translations/custom_other_translations.de.po --type=customized --override=all -y
drush cr -y

drush cim -y
drush cr -y
  • 2
    Database updates always need to run before configuration import.
    – leymannx
    Commented Jul 9, 2021 at 15:22
  • You could be right on that, normally. But I am pretty sure we had some reason we did put it there later on while running in trouble with some config splits. Will re-check this.
    – macbert
    Commented Jul 9, 2021 at 17:27
  • corrected the order in between
    – macbert
    Commented Jul 9, 2021 at 19:14

Use drush deploy, it calls eveything in needed order + as bonus you can use https://www.drush.org/latest/commands/deploy_hook/ which will allow you to manage content changes with new updated/imported structure.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.