Config Sync Basics in Drupal 8

The classic flow of content and code in websites is code goes up from local, to stage then to prod, and database go down from prod to stage and local. This is all well and fine, but in the world we live in of building a site in a CMS a lot of things we would traditionally call "config" end up in the database. In Drupal common things in the database that you want to deploy to production are Content Types, Blocks, and Views. So how do you take an existing website that the client is using and add a new feature that includes a new content type on a view to output it on the page? Back in Drupal 7 you would push up code needed, and quickly click all the buttons again on live and hope you don't miss anything. In Drupal 8 we have Configuration Synchronization built in, meaning we can easily export config into code, push it up and import it into the live site.

Getting Started

The good news is syncing config in Drupal 8 is core, so if you have a Drupal 8 site you already have all you need to get started! To do the Extend section of you site and turn on the module called "Configuration Manager". Once that is turned on you will have a new section in the Configuration > Deveopment tab of your toolbar called "Configuration synchronization" which sends you to /admin/config/development/configuration. From there you have tabs for Sync, Import and Export. There are a couple ways to do config in Drupal 8, through the GUI you can download a full zip of all your config, then go to your live site and import it, or the way I do it is through the CLI using either Drush or Drupal Console. The advantages of doing it with Drush or Drupal Console is it will automatically get placed into your site directories and you can track that in git, for this blog we will only discuss how to do it that way. I also will only talk about export/importing with Drush as doing it with Drupal Console is almost exactly the same so there's no reason to keep mentioning both.

By default if you export config with drush it will place it in your sites/default/files directory, I'm not sure why but if you're plan is to track it with git you don't want that. Luckily changing the default path is as easy as a quick line in your settings.php to say where you want to place it. I generally place it in the root of my repo, but outside of my drupal docroot in a directory called config. That is done by adding the following two lines to your settings.php

$config_directories = [];
$config_directories[CONFIG_SYNC_DIRECTORY] = '../config/default/default';

With that config when you run the config export command drush cex it will out put it to that directory instead of in sites/default/files. The first time you run that command you will have a lot of config, as it's every single configuration in Drupal, it will look like the following.

Now that you have that, if we go and change the site name in the GUI and run drush cex again you will see only one config file has changed like below.

Now for fun lets go and change that file in code, then run the import command drush cim and see it notice that change and if you import it and go to your site it will now have a new name.

So we updated the field of name in system.site.yml and then below we run the import command.

Splitting Config

Okay, you now know how to import and export config on your site, good for you! here we have created a new issue we need to solve. If every module and config is tracked in git, what if locally I want something else on than is in Production, how would I keep that from getting pushed to the live site? Enter the module Config Split which does just that. Config Split lets you define splits per whatever conditions you want, I generally break in into local, staging, and production. So locally you have all your modules you need enabled for building your site like Devel, and caching turned off and on the live site you have all your caching modules turned on.

To get config split working you need to enable the module, configure your settings.php to auto turn on and off splits based on whatever you decide, and configure your splits in Drupal. First in your settings.php you need to turn on and off configs based on something, we use the environment variable of SITE_ENV that we create on each server as an easy way to know what environment we're on, in mine I have the following configured.

$site_environment = getenv('SITE_ENV');
$config['config_split.config_split.local']['status'] = FALSE;
$config['config_split.config_split.dev']['status'] = FALSE;
$config['config_split.config_split.prod']['status'] = FALSE;

switch ($site_environment) {
  case 'local':
    $config['config_split.config_split.local']['status'] = TRUE;
    break;
  case 'stage':
    $config['config_split.config_split.stage']['status'] = TRUE;
    break;
  case 'prod':
    $config['config_split.config_split.prod']['status'] = TRUE;
    break;
}

Next you need to setup your splits in Drupal which you can do by going to Configuration > Development > Synchronize > Configuration Split Settings. From that page you can add a new Split and fill it out like this.

You can name you split whatever you want, but make it something that's understandable, and it affects the machine name needed in you settings.php. The folder section is important because that's telling Drupal where you want that config, the normal setup is to place it in a sibling directory of your normal config. I put my normal config in config/default/default so the local goes in config/default/local. In the next section you define what actually goes in that split. For this test I have only selected the Devel module, which means every config for Devel including it being turned on goes into the Local directory. So now we export config and you will see in the local directory only some devel settings.

Great you now have Config Split working! A further test is we can update the site name again only in the local directory and if we import that it will update the site name over what it in the main config directory.

Wrapping Up

Config in Drupal 8 and Config Split are complete game changers. Now you can create tons of configuration locally, and push it up to a site and import it and it's almost a guarantee it will work every time. Then the ability to push different configuration to different environments removes the headache that syncing config would create if it had to be the same everywhere. It's a great tool and if you're building a site in Drupal you really should be using it, and hopefully this blog post removed some of the complexity around it making it more approachable for you.