I have never been a fan of distributions in Drupal. They can be hard to keep updated, cannot be retroactively added to a site, do not allow mixing and matching of features, and you're often at the mercy of the distribution maintainers. As such, all of the Drupal sites I've built in the past few years are Core and Contrib, with a smattering of Custom development when necessary. Drupal Recipes represent a significant shift in how Drupal sites are built, moving away from complex distributions and towards a modular, composable (something can be put together from multiple parts or components) system. Recipes offer a way to apply pre-configured functionality, themes, and even content to a Drupal site.
It basically gives you hours of work by a Drupal expert with the click of a button, all with Drupal best practices in mind.
Key Concepts
What are Recipes?

- Recipes are a way to apply composable configurations and (eventually) content to Drupal sites. They are a lightweight method to add functionality, moving away from the traditional complexities of distributions and install profiles.
- Recipes are designed to be less complex and require a less significant commitment than previous solutions.
- Recipes are essentially scripts executed once to set up a site, rather than modules providing ongoing functionality. They are not a replacement for modules and are not dynamic after being applied. One speaker from the videos below remarked: "After you're done with using that recipe it's not part of the site. There's no trace of it except that the configuration and those modules are in there now - the recipe can be forgotten."
- Recipes are primarily defined by recipe.yml and composer.json files within a directory, along with optional config and content folders.
- Recipes can install modules and themes, apply a module’s default configuration, selectively apply configurations, and perform config actions.
Composability and Granularity:
- Recipes are composable, meaning a recipe can rely on other recipes, which are then applied sequentially in the specified order.
- It is considered a best practice to create granular recipes that are combined by "meal" or "site" recipes for building more complex features and complete sites.
- Recipes aim to replace the need for monolithic distributions, allowing for mix-and-match features.
Recipe Structure:
- recipe.yml: The core file that defines the recipe's name, description, type, dependencies (other recipes, modules, themes), and configuration actions.
- composer.json: Manages dependencies. Type must be drupal-recipe. It may include a suggest field, but this is only output in CLI, and may be included in Project Browser in the future.
- config directory: Contains static YAML configuration files that are imported.
- content directory: Contains YAML files defining content entities to be created by the recipe. Content must be placed in subdirectories keyed by entity type ID.
- Example: recipe.yml file from the Drupal CMS Blog recipe:
- name: Blog
type: Drupal CMS
description: Adds a blog post content type and listing page.
recipes:
- drupal_cms_page
install:
- add_content_by_bundle
- menu_link_content
- selective_better_exposed_filters
config:
strict: false
import:
system:
- system.menu.main
actions:
user.role.content_editor:
grantPermissions:
- 'create blog content'
- 'delete blog revisions'
- 'delete any blog content'
- 'edit any blog content'
workflows.workflow.basic_editorial:
addNodeTypes: ['blog']
- name: Blog
Configuration Handling:
- Recipes don't just load all config from modules; they use a process of import.
- Basic settings file is installed by default, whereas config entities are optional.
- Config can be selectively brought in from modules by listing those entities in the recipe's yaml file.
- A recipe can completely override config or choose to ignore it.
- Recipes can also alter existing site configuration.
Config Actions:
- A powerful feature that provides a more flexible method to manipulate site configuration.
- Config actions can be applied globally or to a specific type of config entity.
- Config actions are extensible via an API, allowing modules to define their own custom actions.
- Common config actions include:
- simple_config_update: Changes a specific setting.
- create_if_not_exists: Creates a config entity if it doesn't already exist; this is critical for maintaining idempotency.
- set_component: Add items like fields to forms or view modes.
- set_third_party_setting: Changes third-party configuration values.
- grant_permissions: Sets permissions for roles.
- add_node_types and add_taxonomy_vocabularies: Applies workflows.
- add_to_all_bundles: Adds a field to content types, etc.
- Block placement configurations.
Applying Recipes:
- Recipes are applied to a site, rather than "installed."
- Recipes can be applied via Drush (drush recipe) or through the Drupal UI in Project Browser (though this is currently in alpha).
- Order of application:
- Apply other recipes.
- Install modules and themes.
- Import basic module config.
- Import specified config entities.
- Import configuration files.
- Apply config actions
- Import content from the content folder.
- Requires a cache clear after applying to make changes available.
- Recipes should be placed in a recipes directory that is a sibling to the web directory for chaining to work correctly currently.
- Recipes are not dynamic, meaning once applied, the recipe itself does not continue to affect the site.
IdemPotency:
- Recipes should be idempotent, meaning they can be applied multiple times without causing errors or changing the results. This is achieved through strategies like "create if not exists".
- This is important because recipes can be included as dependencies in multiple recipes and applied at various times.
Content Creation:
- Recipes can provide content, created from YAML files, with content organized into subdirectories by entity type.
- The code to do so was moved to core from the default_content module.
- The default_content module is still useful for generating the necessary yml files.
Use Cases
- Recipes can replace distributions for new site creation and also add new functionality to existing sites.
- Examples are provided of recipes that provide functionality such as events, breadcrumbs, and alerts
- Recipes can provide different "meals" (whole site setups), "dishes" (individual features), or "ingredients" (very small individual config recipes).
- Recipes can be used to provide features or for site setup.
Limitations
- Recipes are still under development and are considered an experimental API in Drupal 10. They are "baked" into Drupal CMS.
- There are no formal ways to "uninstall" or reverse a recipe, meaning the site needs to manually remove configuration that was provided if the recipe is no longer desired.
- There is no mechanism for a recipe to validate config prior to application. This is an active area of development. "the current recipe level inclusion does not work because it entangles the recipes too much the idea is to be able to say something like if this rooll does not exist you can get it from this recipe"
- When applying a recipe, config is compared and fails to apply if there is a mismatch, requiring the recipe to be created specifically to anticipate existing configurations.
- Recipes do not clean up after themselves if there are errors, potentially leaving broken sites, so recipes should only be applied in local development environments where config is managed via git and can be rolled back. "I would definitely only run recipes specifically at this point like on a local development environment and where I'm then like I have my site it's fresh I have I know that my config is all exported it's all clean and now I apply my recipe and now if it messes something out I can just use like git to clear everything out and reset everything."
- Recipes do not natively detect or warn of conflicts between modules installed by multiple recipes or existing configurations.
Roadmap & Future Development
- Phase One Complete: Core functionality to apply recipes and the API to expand config actions has been implemented. When you install Drupal CMS, you are using recipes to create the Blog, News and other featured sections.
- Ongoing Work: Unpacking Recipes: Ability to move recipe dependencies into the site's composer.json when the recipe is removed, allowing the site to continue functioning without the recipe present.
- Config Validation: More robust validation of config before applying a recipe.
- Placeholders: Allow for dynamic labels that are substituted in config action.
- User Input: Add functionality to prompt a user for values, such as Google Maps API keys.
- Block Placement Actions: Flexible block placement configurations that do not require specific theme knowledge.
- Documentation: Move documentation from GitLab to Drupal.org.
- Recipes Discovery Improve ways of browsing and discovering recipes in Project Browser
- Reversing Recipes: Allow recipes to be unapplied.
- Integration with Project Browser is expected, which should allow for UI creation of recipes.
- A new system for managing config validation will allow for config snapshots/rollbacks to be created prior to applying recipes.
Final Thoughts
Drupal Recipes offer a promising new approach to building and extending Drupal sites. They allow people new to Drupal to build sites more easily. Recipes could be used to create a library site, an event workflow site, or other types of sites.
Recipes are active in Drupal CMS, though not in Drupal Core as of yet. There is no UI, there is no way to select a recipe during installation, and they can't be removed and revert the site to its previous state. That said, it seems to be the future of quickly adding feature sets to your Drupal site, saving time and making it easier for non-Drupal experts to get a site up and running (the goal of Drupal CMS).
Resource Links:
Spin up a Drupal CMS demo (6 hours) - https://www.drupalforge.org (highly recommended)
https://www.drupal.org/about/starshot/initiatives/recipes
Some video resources:
(terrible audio but still a good video)