For the last two years we have been giving trainings and presentations at various Drupal events about configuration management and its new workflows in Drupal 8. One of the recurring questions has been:
How do I keep some configuration from being deployed? For example the devel module and its configuration?
Until now we have answered to use drush with the --skip-modules flag and then to gitignore the configuration for devel. But then you can't share the development configuration and the process is error prone when there are more modules and other configuration items that depend on the configuration you gitignore.
For some simpler cases where configuration needs to be different between environments (for example the error verbosity) the configuration override system allows to override the configuration in settings.php. This is a solution for some cases, however, you can not override which modules are enabled or override configuration that doesn't exist.
Enter: Configuration split!
Our new module Configuration split splits the configuration when exporting it with a special Drupal Console command. It can be configured to split out enabled modules and given blacklisted configuration and it will then separate all the configuration that is dependent on the listed modules or configuration. The module's settings also allow to set a folder to which the separated configuration will be exported to.
That way the configuration set which you use to deploy configuration between different environments is a subset of your development configuration and the trusty configuration system of Drupal 8 can be used unharmed.
Of course when importing with the special command the split configuration is merged back, allowing you to keep your development configuration in place.
"To split" is a synonym for "to break" and as such "Configuration split" has a dangerous ring to it. This is on purpose because the exported subset is on purpose not what you have on your development site and not what you have locally tested. So you need to compensate that with a workflow that imports and verifies the configuration you are going to deploy. This is better than to import and export individual configuration because Drupal needs the whole set of configuration to do its checks.
How do I use it?
Download and enable the Configuration split module like any other module. Then configure it under admin/config/development/configuration/config_split. Set the split folder to a different folder than your normal config sync folder. If you want a prettier interface, consider using Chosen. Then use the Drupal Console command config_split:export and config_split:import to export and import respectively.
Let's look at the devel example from above. We typically version the configuration outside of the webroot in ../config/sync as seen by Drupal. (In the project root when starting a project with drupal-composer/drupal-project.) So the folder we specify for config_split would be ../config/dev. The module to filter would be Devel and the rest can be left empty. The devel.settings will be detected automatically. Note though that the system.menu.devel does not depend on the devel module and can not be detected automatically, but it is easy to add it to the blacklisted config and it could theoretically be deployed without breaking anything.
The resulting config_split.settings.yml could look something like this when exporting it:
Finally the following command will export the configuration to the default sync directory without the devel module enabled and export the devel configuration into the dev directory. web$ ../vendor/bin/drupal config_split:export
Now if you would import the configuration through the UI or with drush cim the devel module would be un-installed, and you can do that to see the site without its development configuration. However, If you want the development configuration to stay or become active and the devel module installed use the following command: web$ ../vendor/bin/drupal config_split:import
How does it work internally?
We implemented a StorageWrapper that allows filters to interact with the configuration after it has been read and before it is written to the wrapped FileStorage during the import and export operation. The SplitFilter has a secondary storage and decides where to read from or write to. This is a very similar concept to what drush does with its --skip-modules flag since we will want to easily integrate this with drush in the future.
What comes next?
The module is still in an early development stage and some more additions in the scope of splitting configuration could be added. The subset without the split configuration could be verified after exporting it and we could warn the user if it couldn't be imported. Or for example we currently use only config_split.settings but if the need arises we could support multiple split configurations. Or we could add a "gray list" to ignore some configuration that exists rather than removing it when splitting, essentially making it a configuration override outside of the scope of Drupal's runtime. This could be useful when maintaining several sites that are almost the same but all have their little "special snowflake" configuration which in turn could be synchronized with the normal workflow.
It is important to understand that the configuration system of Drupal has limitations that are there for a good reason. Most of them are to ensure data integrity and robustness and reliability of the synchronisation and so on. In other words measures to protect you from accidentally breaking your site. Using tools like config_split or drush --skip-modules you circumvent some of these security and integrity checks so use them with caution.
Since the module is not required for the regular functioning of a Drupal 8 site (it can even be used to blacklist itself) it can already be used in the development process of your current projects already. Your feedback is welcome, see you in the issue queue.