Problem/Motivation
Currently when a recipe is reapplied, config as provided is compared against existing config in the active config storage and an exception raised if there's a difference.
As determined in #3283900: Define recipe runtime configuration update requirements, when the recipe has been previously run, this comparison will fail when any of three commonly occurring situations apply:
- The config has been altered by a config action. Example: Recipe A provided a user role and Recipe B added a permission to the user role.
- The config has been customized by a site administrator. Example: Recipe A provided a user role and a site administrator added a permission to the role.
- The config as provided has changed. Example: Recipe A provided a view when it was last installed and now provides the same view in a slightly different form, such as a field added to a display.
The first of these issues may be mitigated through #3304910: Compare against a config snapshot when (re)applying a recipe. Still, taken together, it's expected these common sources of differences will frequently prevent reapplication of recipes, significantly weakening the applicability and benefits of recipes.
Proposed resolution
When there are differences between config as provided and config in the active storage, determine what changes are available and merge them in.
As well as solving the problem of ensuring recipes can be reapplied, this will essentially make recipes and extension-provided config updatable, achieving a longstanding aim currently met in contrib by workarounds like Configuration Synchronizer and Update Helper.
Doing so will require:
- #2960870: Snapshot configuration as installed and updated from recipes and extensions
- #2960867: Add a ::normalize() method to config entities to support comparing extension- and recipe-provided to installed configuration
- #2960874: Support 3-way configuration merging
Comments
Comment #2
joachim commentedShould #3307647: Support option of reverting to config as provided when (re)applying a recipe also be a child issue of this?
I think the main problem that needs to be solved here is how to present config diffs to a user in a way that's clear. Diffs of YAMLs are a LOT clearer than diffs of PHP like we have on D7 with the Features module, but it still requires developer knowledge of what the different properties all mean.
I've been wondering about the possibility of building something that automatically generates a config form based on the config schema.
I've built something similar for Module Builder, which dynamically builds a form based on a TypedData-ish schema given by Drupal Code Builder -- see https://git.drupalcode.org/project/module_builder/-/blob/8.x-3.x/src/For....
I started having a brief play around with the idea recently, but got stuck in the innards of the config system -- I wasn't able to figure out how to ask the config system for the schema for a particular config object.
Comment #3
joachim commentedSee also https://www.drupal.org/project/migrate_api/issues/2624746
Comment #4
alexpottAn aside to this issue...
@joachim wrote
We actually have this in core - for the config translation interface. And I'm pretty sure the config_inspector module does similar stuff.
Comment #5
thejimbirch commentedComment #6
deviantintegral commentedOne of our team members recently created a proof of concept to test out recipes as they exist today, and we pretty quickly ran into this. There's three scenarios I can think of where functionality like this would be useful:
As is, I don't see Recipes solving #3 for us - for it to be worth our time creating and maintaining, it's got to work for all of our projects, both greenfield and inherited. Otherwise, it's more effective for us to treat these things as documentation and not code, even if that means annoying point and click (and copy-paste) setup.
Given it's been a year and a half since the last substantial comment, it'd be great to know if this feature is still in scope with the current state of the initiative and where it currently ranks in comparison to other work.
Comment #7
thejimbirch commentedHi,
This issue is in my phase 2 roadmap under the Improve the recipe application process epic. See #3446089: [Meta] Recipes Phase 2 Roadmap.
I love the idea of your #3, and already have some "snack" sized recipes like a 90 Day Password Policy and YouTube Lite Embed.
We just landed recipes and default content into core a few weeks ago as experimental. Our goal for phase 2 is to iterate and improve, and work to ensure recipes as a foundation can support the Starshot initiative.
Most of the work in this initiative has been done by a very small group. If anyone is interested in helping move this issue forward, we would gladly accept the help.
We have an asynchronous meeting every two weeks.
#3269687: [Meta] Recipes Initiative meetings - Next: February 10th, 2026
We monitor the #recipes channel of the Drupal slack.
We have a Recipes and Starshot Webinar scheduled for June 11, 2024 - 15:00 - 16:00 GMT
Comment #8
deviantintegral commentedExcellent, thanks for the update! I'll be sure to point members of our team here if they're looking for contribution opportunities.
Comment #9
thejimbirch commentedThank you!
Comment #10
bsnodgrass commentedmoved to Drupal Core, per https://www.drupal.org/project/distributions_recipes/issues/3513044
Comment #11
drale01 commentedI’m seeing a similar situation, and I think the issue ,in my case, could be solvable.
I created a standalone child recipe for a content type that only has Body and Image fields. The child recipe also contains configuration for the content type’s “Manage form display” and “Manage display”. When I install this child recipe by itself, everything works and the configuration imports correctly.
Next, I made a parent recipe that adds a Paragraphs-based field to the same content type. Since the parent recipe depends on the child recipe, I nested the child recipe inside it. The parent recipe includes its own “Manage form display” and “Manage display” configuration for that content type, which includes the new Paragraph field. So the config file names are identical to those in the child recipe, but expanded to support the paragraph field.
When I install the parent recipe, it always brings in the child recipe’s configuration instead. That means on both the “Manage form display” and “Manage display” screens, the paragraph field ends up disabled.
The only way to get the parent recipe configuration to win is to delete the “Manage form display” and “Manage display” config files from the child recipe. But then the child recipe is no longer standalone.
It would be logical if the parent configuration could override the child configuration when both are present. Surely, it only works in cases where the configuration doesn’t exist at all before the recipe is applied.
Comment #12
thejimbirch commentedNested recipes are not recommended or supported. You can have recipes depend on each other, but they should be their own packages.
In your situation, you should use config actions to update the “Manage form display” and “Manage display” settings instead of bringing in a whole config file.
Comment #13
drale01 commentedExcellent, this is the solution to my problem.
I set in
recipe.ymlAnd when installing a recipe that depends on another one, I got the modified configuration.
I didn’t express myself correctly about the nested recipe — I just wanted to explain more clearly that I want each recipe to be standalone, and if one recipe depends on another, it should be able to modify the configuration of the recipe it depends on.
Comment #14
liam morland