Deployment Best Practices

While the exact steps you take to deploy Craft CMS will depend on your hosting setup, we recommend these general best practices to encourage smooth, predictable deployments.

Consider reviewing the Hosting & Deployment documentation for additional workflow tips.

Commit Template & Config Changes #

It’s best to limit config and dependency changes to local environments where they can be tested, committing explicit records of those changes to be used by the deployment process:

Be Prepared #

A few precautionary steps can drastically reduce the impact of most human and technical errors:

  • Back up your database at sensible intervals, whether they’re scheduled snapshots or part of the deployment process. Test the backups periodically to be sure they’re reliable and easy to restore.
  • Back up Asset Volumes in case a content editor accidentally hard-deletes any files. (Most cloud storage providers can be configured to enable versioning, and local assets can be included in snapshot backups.)
  • Ensure every deployment environment can pass Craft’s environment check, giving PHP at least 256MB of memory and a 120-second max execution time per Craft’s server requirements.
  • Ensure a developer with Composer knowledge has SSH access to the deployment machine for troubleshooting in case anything goes wrong.

Follow Deployment Steps #

Ideally, deployments would be automated with Buddy, GitHub Actions, Travis CI, or a similar service to work quickly and automatically, avoid human error, and immediately alert you to any issues.

Deploy Flow Using Up

Regardless of how you’re managing deployments, however, it’s important to follow these steps in order:

  1. Pull updated files into place with git pull <your-remote-name> (i.e. origin) and update dependencies by running composer install --no-interaction.
  2. Run php craft up to run pending Craft, plugin, and/or content migrations and apply project config YAML changes.
  3. You’ll often need to clear caches as a last step, which can also mean scrubbing PHP’s OPcache or issuing purges for a CDN.

If you use content migrations that depend on project config updates happening first, you can separate structural and content changes into their own steps. This example does exactly that and includes flags for an automated, non-interactive deployment process:

php craft update/composer-install --interactive=0
php craft migrate/all --no-content --interactive=0
php craft project-config/apply
php craft migrate --track=content --interactive=0

As of Craft 3.7.13, this process can be simplified with the up command:

composer install
php craft up

Never pass Composer’s --no-plugins option updating Craft.
This disables Craft’s own Composer plugin that identifies Craft plugins and populates vendor/craftcms/plugins.php.

Mind PHP Versions Across Environments #

When you run composer update, dependencies are updated for that environment’s PHP version and the result is written to composer.lock. Running composer install downloads whatever’s specified in composer.lock without concern for the current environment’s PHP version, which could lead to runtime issues.

You can use the config.platform.php property in your project’s composer.json if you’d like to specify a target PHP version and limit the potential for cross-environment issues.

If you’ve followed the steps above and are encountering problems, see Troubleshooting Failed Updates.

Applies to Craft CMS 4 and Craft CMS 3.