Level Up Your Drupal 8 Configuration Management – Make Drupal Configuration Work the Way You Do!
The rise in Drupal 8 installations has brought with it an increased need for environment-based Drupal configurations. In 2018, there were 241,000 Drupal 8 sites up from 159,000 Drupal 8 sites in 2017, representing a 51 percent increase year over year, according to Dries Buytaert. Having attended DrupalCon in Nashville this year, I was inspired to write a post about my experiences with this and share how a Drupal developer can devise a comprehensive approach to managing Drupal 8 configuration across multiple environments.
What is Drupal 8 Configuration Management?
Configuration Management is a new Drupal core system that allows database configuration to be exported to YML files. This makes the process of moving configuration settings from one environment to another much easier than in previous versions of Drupal. For example, if you make a new View page in the development environment and want to deploy it to the testing environment, it’s a matter of exporting the configuration, committing it to version control (git), and deploying/importing it on the other environment.
In Drupal 7, configuration and content are both stored in the database. This left the task of moving configuration to other environments to contributed modules like Features. This worked well enough, but it wasn’t quite as effortless as it could be.
Drupal 8’s configuration system is miles ahead of Drupal 7. In Drupal 8 Core, configuration for most site settings and definition of structural pieces of the site can be exported with one click of a button or a single drush command. You can then commit and merge configuration changes in source code control, deploy the configuration, then import it in to the destination environment. Life is definitely easier in Drupal 8!
On a recent project, I ran into a few situations where the off-the-shelf Drupal 8 configuration approach was too heavy-handed for us. Moving configuration between environments would cause undesired changes to staging and (ultimately) production environments. We typically work around this using multiple configuration directories for each environment (I’ll illustrate how that worked in a moment).
At Bounteous, we take a component-based approach to building many reusable content elements for sites. This gives our sites a robust experience to construct pages with the components where our clients want. This approach saves effort for everyone when a site needs a new landing page.
This approach uses a lot of pieces which are handled in configuration: custom block types, Paragraphs, Page Manager pages, Panels with In-Place Editor, and more. Configuration export works great to get new components (like that fancy new block type “Hero image carousel”) from my local environment to development!
Using this component-based approach, the client is using instances of blocks as “content” and do not see them as configuration. This is awesome for content-building experiences, but can be perilous when the client has a long change management process before code (containing our blocks configuration) can move to production. This is why I needed to find a better way.
The Previous Way
On previous projects I have used multiple configuration directories—one per environment. We would also have override configuration files in a set of folders. This can be illustrated with the following directory screenshot:
Configuration management is a bit of a dance using this approach, but it works. Here’s the high-level workflow for the code, intentionally leaving out things like reviews, testing, etc. for brevity:
- Build new feature locally
- Export configuration to “dev” directory, commit configuration
- Import configuration on development environment
- To move to “stage”, copy configuration to stage
- Copy the “dev2stage” configuration into "stage" overwriting what is there
- Import configuration on stage environment
- Uninstall “dev” modules not needed on stage
- Get a configuration export from production, put into "prod" directory
- Copy "stage2prod" configuration to "prod"
- Copy configuration from "stage" to "prod," review the file changes to revert undesired changes
- Commit configuration and deploy.
In the dev2stage and stage2prod directories are yml files for specific configuration we don’t want to accidentally change when moving between environments--things like Google Analytics configuration and API keys.
We went down this road when there weren’t a lot of utility modules to help with configuration management. After reading through this process, I’m sure you think it’s complex…I certainly do. It kind of is, but it’s been manageable with some scripts to help out and a careful eye reviewing everything along the way.
This approach can work when there are minor differences between environments. But with more complexity in the site and more differences between environments, this quickly loses sustainability.
My New Approach
I recently led a team of developers to build a site for a new brand that a long-time client was launching. This was the perfect opportunity to survey the Drupal 8 configuration management landscape to see how we can make configuration management more streamlined.
Considerations / Wish list:
- Module install/uninstall based on the environment
- Enable dev tools (devel, webprofiler, generate, etc.) on local and development; not enabled on all other environments
- No UI modules (Views UI, Field UI, etc.) enabled on production
- Per-environment settings
- API keys (dev/test only connects to credit card processor ‘sandbox’, prod always connects to live processor)
- Site/Store email addresses different on each environment
- Turn on all the caching on production and test, but not on dev or locals
- Blocks used as content aren’t modified on configuration import
Part One – Per-environment Settings
Configuration overrides are the easiest way to handle minor changes in configuration between environments. Configuration overrides are handled in settings.php by changing configuration values using the $config variable.
In our case, the client site is hosted on Acquia and they provide an environment variable which makes detecting the environment super simple. This variable is named $_ENV[‘AH_SITE_ENVIRONMENT’], and contains a value such as dev, test, stg, prod, or ra to indicate the current environment. Here’s a snippet from our settings.php file that illustrates this:
If you aren’t hosting on Acquia, you can use (or create) a similar variable on which to set environment-specific configuration.
Part Two – Configuration Ignore
Configuration Ignore is a straightforward contributed module that does what its name suggests - it ignores configuration on import. You can look at the project page at https://www.drupal.org/project/config_ignore.
The key to leveraging the power of this module using the correct configuration entities to ignore. The module adds a form at /admin/config/development/configuration/ignore where you input a list of configuration names to ignore. It supports patterns, so you can exclude large chunks of configuration easily.
We need to not overwrite/delete configuration which represents content components on the site. Most of these components are blocks, so I’m looking to exclude the blocks built as content, but not the structure (fields, display settings, etc.) of the blocks themselves.
The entries you put in this form follow the file names of yml files in your site’s config export directory. Looking at the config directory for the site, I can see that these content blocks are in files which start with ‘block.block’. Also, as new landing pages are created using the Page Manager, we want to make sure that these aren’t touched on configuration import. These start with “page_manager.page” and “page_manager.page_variant.”
Here’s what the configuration form of Config Ignore looks like for our site:
Bonus tip: be sure to look at the help information on this form, it provides a lot of examples of how to use this module!
Part Three – Configuration Split
This is the real heavy lifter of this configuration management scheme. It does what I consider magic. I hope I’m not underselling this module! You can find the project page for this module at https://www.drupal.org/project/config_split. Here you’ll find some in-depth documentation on how this module works as well. For my use case, I only needed to either turn on or off a module depending on environment—so I only used “complete splits” (whole module settings) and not “conditional splits.”
In short, Configuration Split allows us to carve out certain module configurations and place them into another directory. Then with some clever per-environment configuration overrides (remember Step One), the configuration is either included or excluded on configuration import.
Taking the example of turning on/off UI modules depending on the environment, I set up a configuration split to handle this. My helpful hints for this are:
- Do a configuration split for each group of module types (development modules, UI modules, caching modules, etc.)
- When creating the split, enable the modules first so that the Config Split module knows what modules the site is working with.
- Create the configuration split directory on the same level (e.g. as a sibling) of the regular config directory.
Create the split by providing a name and a directory
Then in the Complete Split section, select the modules to exclude:
From this list, I selected Views UI, Field UI, and REST UI.
Once the configuration is saved, perform a configuration export. If the modules include configuration settings, those yml files will appear in the directory created.
We created splits for the following items:
- Development modules
- Caching modules
- UI modules
- Logging modules
The last step is to update the settings.php file to either enable or disable that split based on the environment. TRUE turns on the modules/config in the split, FALSE uninstalls the modules/config in the split.
Here’s what this looks like for the ‘prod’ section of settings php:
So far, this configuration approach has worked well for us and our client. We have been able to confidently export configuration from development and import it into staging and production without fear of unintended configuration changes. Over time, we’ve added and updated settings for our configuration management scheme as new modules were created or the client needs changed for specific items. The key when using any Drupal configuration management approach is to understand that it’s not “set it and forget it,” but an ongoing process to maintain a site’s configuration for the long term.