Cooking Up Convenience - Symfony Flex's Recipes and the Drupal Recipes Initiative
Tags: symfony, drupal
Published: 2023-10-30 00:15:19

This article [originally appeared on Symfony Station](https://symfonystation.mobileatom.net/Symfony-Flex-Drupal-Recipes).

Symfony's Flex Recipes (starter sets of functionality) provided part of the inspiration for Drupal's new Recipes Initiative (as opposed to its current distributions).

This article will compare the two. Since the Drupal recipes are just coming to the web development kitchen, we will look at them in more detail. However, let's start by looking at Flex.  
  
## Symfony Flex Recipes  
  
According to Symfony, "Symfony recipes allow the automation of Composer packages configuration via the Symfony Flex Composer  
plugin. Flex is innovative tool that makes adding new features as simple as running one command. It's also the reason why Symfony is ideal for small micro-services or huge applications.  
  
This makes Symfony different from any other PHP framework! Instead of starting with a bulky app with every possible feature you might ever need, a Symfony app is small, simple and fast.  
And you're in total control of what you add."  
  
To master Symfony recipes, let's take a step backwards. Symfony projects start with a composer.json file containing several Symfony libraries. An important one is symfony/flex.  
As noted above, Flex is a composer plugin that adds more features to composer. In fact, it adds three capabilities to composer.  
  
### Flex Aliases  
  
The first capability is Flex aliases. Visit https://flex.symfony.com to see a page of packages. Aliases include template, templates, twig, and twig-pack packages. The idea between Flex aliases is simple. 

You type "composer require templates" in the command line. And then, internally, Flex changes that to symfony/twig-pack. Ultimately, that is the package that Composer installs.  

Most of the time, you can just "composer require" whatever you want, like composer require logger, composer require orm, etc. It's a shortcut system that installs packages.  
  
### Flex Packs  
  
The second capability of Symfony Flex is unpacking packs. The original package contains just one file: composer.json . It requires other packages. This is what's known as a Symfony pack. It's a fake package that helps us install other packages.  

In Symfony, if you want a rich template engine for your app, you need multiple packages. But instead of adding them manually, you can "composer require symfony/twig-pack" and automatically get them. 

When you install a "pack", Flex  automatically "unpacks" it. It finds the packages that the pack depends on and adds those into your composer.json file. So, packs are a shortcut where you can run one composer require command and get multiple libraries added to your project.  
  
### Symfony Recipes  
  
As you can see, Symfony Flex makes it dead simple to install a package and get everything you need to start working on your Symfony app. It includes new config files, changes to .env, Docker configuration and more. 

The idea is so powerful that symfony/skeleton - the repository used for new Symfony apps - starts empty other than composer.json. Files like src/Kernel.php , bin/console and config/services.yaml are added to your project via recipes.  
  
Let's look at Twig in detail to see how this works.  
  
Symfony recipes live in a repository named symfony/recipes . This is a directory organized by package name. There's a Symfony directory that holds recipes for all packages starting with symfony/ .  

The one we're explporing is twig-bundle.  
  
Each recipe has a manifest.json file, to control its actions. The recipe system can only implement a specific set of operations, including adding new files to your project and modifying specific files.  
  
Two very interesting things happen behind the scenes thanks to Symfony Flex.  
  
First, Twig is not the name of a Composer package. It's a Flex alias that points to the symfony/twig-bundle. Flex resolves that alias for Composer.  
  
And second, Flex installs a recipe for symfony/twig-bundle. A recipe is a way for a library to automatically configure itself by adding and modifying files. With recipes, adding features is seamless and automated. Just install a package and you're good to go.  
  
What did the Twig recipe do? 

In addition to automatically enabling the feature in config/bundles.php, it  added 3 things:  

1. config/packages/twig.yaml - A configuration file that sets up Twig with sensible defaults.  
2. config/packages/test/twig.yaml - A configuration file that changes some Twig options when running tests.  
3. templates/ - This is the directory where template files will live. The recipe also added a base.html.twig layout file.  
  
### Updating Recipes  
  
Later in your Symfony project's life there might be changes to some of the recipes that you've installed. If there are, when you run them you'll see an update available notification. Run "composer recipes:update" to upgrade to the latest version. 

In addition to symfony/recipes, there is also a symfony/recipes-contrib repository. So recipes can live in either of these two places. The recipes in symfony/recipes are approved by Symfony's core team. That's the only difference between them.  
  
  
Starting in symfony/flex 1.18.0 or 2.1.0, a new composer command became available, recipes:update.  This command generates a "diff" between the originally-installed version of recipe and the latest version, then leverages git to apply that patch.

Thus, upgrading recipes is similar to merging two branches together via git. The majority of the time changes apply cleanly. If they don't, you get a familiar git-style conflict that you can resolve.  
  
So that's Symfony Flex Recipes and why they're magnificent.  
  
## Drupal Recipes  
  
Let's start with a quick note about the differences between Drupal distributions with their profiles and the new recipes initiative.  
  
Drupal distributions provide a predefined set of modules and configuration that define a specialized website solution. For example, a commerce, government, or intranet website. The Drupal community has admitted that distributions can be overly complicated and challenging to maintain.  
  
Drupal Profiles, on the other hand, are subsets of distributions and are included in Drupal core. Drupal core comes with three installation profiles: Standard, Minimal, and a Demo site (Umami).  
  
Installation profiles determine the set of modules, themes, and configurations that are included in a distribution.  
  
Being Drupal none of this has anything to do with the new [Drupal Starterkit Themes](https://www.drupal.org/docs/core-modules-and-themes/core-thems/starterkit-theme/).  
  
### The Initiative  
  
Drupal founder Dries Buytaert introduced the new concept of would-be "Recipes" in his DrupalCon Portland 2022 Driesnote where he called them “Starter templates.” As examples, Dries mentioned a template of a product site that could include a carousel, a web form, a bunch of content types, etc.  
  
New to Drupal 10, the **recipes initiative's** goal is to provide a modern replacement for distributions. A 'recipe' is a composable piece of site functionality and features bundled together.  
  
Its goal is to uncouple an installation from its base. This will make Drupal installs more manageable and specific to a site’s unique needs.  
  
Like Symfony Flex, Drupal recipes are a modular approach, but immediately add more functionality.  
  
According to Drupal, "Drupal recipes allow the automation of Drupal module install and configuration via the user interface and via the Drupal recipe runner."  
  
As part of the larger Drupal strategic initiative, site-builders & developers can certainly benefit from the improvements to be provided by the recipes initiative.  
  
Again, Drupal 10 recipes are expected to provide more flexibility and ease of use to site builders and developers, allowing them to create custom solutions that meet their specific needs.  
  
Drupal also notes, "ideally Drupal recipes would not configure an entire site themselves but would break out their functionality into smaller recipes that can be reused by other Drupal recipes."  
  
### Drupal Recipes Objectives  
  
One of the primary goals of the Recipes Initiative is to reduce the challenges site maintainers and developers face with distributions.  
  
They want to:  
  
- Allow users to install multiple Drupal recipes on the same project.  
  
- Install a recipe at any point in a project's life cycle.  
  
- Simplify the process of maintaining the multisite architecture.  
  
- Make updating easier.  
  
- Make it easy for Drupal recipes to provide demo content.  
  
  
### Drupal Recipe Benefits  
  
Benefits of using recipes include:  
  
 - **Being installable at any time.**  
  
One of the main benefits of recipes as opposed to distributions is that Recipes be installed at any point in time. Eventually, his should include the option to find and install with Drupal's admin UI via Project Browser — another innovation that’s coming to the Drupal core.  
  
- **Mixable and composable.**  
  
You can also mix and match as many recipes as you like. Recipes are composable with other recipes to create recipe kits.  
  
- **Individual components are replaceable.**  
  
Furthermore, recipes do not lock sites into a monolithic setup as distributions do. You can replace individual components as you need them.  
  
- **No need to maintain or update.**  
  
Recipes are applied to websites, not installed on them, which eliminates the difficulties of maintaining anything.  
  
  
### What can a Drupal recipe do?  
  
Recipes have the following functionality:  
  
- Provide a list of other Drupal recipes to apply.  
  
- Drupal recipes can be composed.  
  
- Provide a list of projects to install via composer.  
  
- **Provide a list of modules to install.**  
  
Eventually, this will only install the simple configuration provided by the modules. It should ignore all the configuration entities. This approach means that Drupal recipes don't require a way to remove module provided configuration entities.  
  
- Provide a list of themes to install.  
  
- **Provide configuration.**  
  
You can choose config from the modules a recipe lists. A single wildcard will indicate that all of module's configuration should be created.  
  
- Supply new configuration.  
  
- **Update existing configuration.**  
  
The ability to script configuration updates to the existing configuration is a vital new ability for Drupal recipes. They can use this to add permissions to existing roles and fields to entity displays and views.  
  
- **Provide content.**  
  
- **Add new content**  
  
Maybe update existing content? (at a later date).
  
- Delete content. 
 
- Provide suggested recipes you might want to apply afterwards.  
  
- **Provide tests.**  
  
At a minimum core should provide a test that can be run against any Drupal recipe that proves it is installable.  
  
- **Have the following metadata:**  
  
Name - a short name for the Drupal recipe.  
Description - a longer description of the Drupal recipe.  
Type - groups related Drupal recipes together. The type 'Site' is a special case that allows such Drupal recipes to be listed on the installer.  
  
### A Quick Note about Schema  
  
How are Drupal recipes different from Jakob Rockowitz's Schema Blueprints Module?  
  
Jakob says, "The 'Recipe' initiative and the Schema.org Blueprint module share the goal of providing a better starting point for building out a website's  features and functionality. 

The big difference between these two solutions is the Schema.org Blueprints module does not ship with a predefined content model and configuration. 

Instead, the  Schema.org Blueprints module provides a "blueprint" for creating a standardized and reusable content model based on Schema.org's 900+ types."  
  
### Authoring Recipes  
  
Authoring functionality is actively being created. Currently, implementation will be by hand. One of the goals of the initiative will be to build a CLI command to create Drupal recipes from an already configured site.  
  
A vital part of creating a new recipe is to identify existing recipes to reuse in yours. Site builders will want to apply multiple recipes on their sites.  
  
### Guidelines for interoperable recipes  
  
The initiative's interoperability guidelines:  
  
- **Start with core recipes.**  
  
Prior to Drupal 10, short of patching, there wasn't a way to build on core's install profiles like "standard". Even if you needed the exact same configuration, you had to provide it yourself.  Now the opposite is true. Every conceivable set of recipes should build on the recipes in core. This is the easiest way to ensure recipes integrate with others.  
  
- **Put reusable config in its own recipe.**  
  
As a rule, where a config entity is applicable to different use cases, it should go in its own recipe.  
  
- **Use selective enhancement for maximum flexibility.**  
  
For example, not all recipes that require an article content type will also require tags. So the tags vocabulary goes into its own recipe, an article recipe doesn't require tags, and there's a bridging recipe that selectively enhances articles with tags. Selective enhancement will often mean using config actions to integrate one recipe with another.  
  
### Drupal Recipe Maintenance  
  
The Drupal Recipes Initiative is still under development. This is especially true for maintaining recipes.  
  
An aim of the initiative is to make recipes easily maintainable. The biggest challenge will be what happens when a module providing code for a configuration entity or content entity makes a change that results in an update to the recipe.

When the Drupal recipe is applied to a new site, composer will get the latest versions of the dependencies and therefore any updates that this module ships will not be run against configuration or content provided by the Drupal recipe.  
  
Currently, Drupal is asking if it can use something similar to Symfony's recipe update functionality? 
  
And how will recipes deal with versioning? Should a Drupal recipe store the versions of modules used to create it? Can it leverage this information to provide automatically generated updates to recipes. Or maybe a CLI command to make it easy?  
  
Stay tuned.  
  
### Cookbook  
  
There are some great Drupal recipes to experiment with on this [Recipes Cookbook](https://www.drupal.org/docs/extending-drupal/contributed-modules/contributed-module-documentation/distributions-and-recipes-initiative/recipes-cookbook) page.  
  
They include:  
  
- [kevinquillen/drupal-base](https://gitlab.com/kevinquillen/drupal-base) - Use the best parts of the standard profile on a minimal install.  
  
- [kanopi/drupal-build-starter](https://packagist.org/packages/kanopi/drupal-build-starter) - A more opinionated build on a minimal install.  
  
- [wunderio/next-drupal-starterkit](https://github.com/wunderio/next-drupal-starterkit) - This is a starter template created by Wunder  
for a decoupled website using the open-source Next.js for Drupal. Includes multiple recipes.  
  
  
## Summing it up  
  
As you have seen Symfony's Flex Recipes and Drupal's new recipes are somewhat similar but significantly different.  
  
Flex is more modular and allows customization at a granular level, like Symfony in general. It's one of the many things that make Symfony awesome.  
  
The Drupal Recipes Initiative recipes allow more opinionated and comprehensive sets of functionality to be easily added to installations. This will be very helpful to agencies, in particular. It's also a vast improvement on distributions.  
  
Hopefully, Drupal can implement them faster than they usually bring initiatives into core. They have great potential.  
  
Thanks for reading, and explore the resources below for more information.  
  
It's time to start coding recipes. Make that cooking with them. ;)  
  
## Resources  
  
### Symfony Flex Recipes  
  
- [Documentation](https://symfony.com/doc/current/setup/flex.html)  
  
- [Repository](https://github.com/symfony/recipes/blob/flex/main/RECIPES.md)  
  
- [View a list of Symfony Flex recipes](https://bit.ly/flex-recipes)  
  
- [More via Symfony Casts](https://symfonycasts.com/screencast/symfony)  
  
### Drupal Recipes  
  
- [Recipes Cookbook](https://www.drupal.org/docs/extending-drupal/contributed-modules/contributed-module-documentation/distributions-and-recipes-initiative/recipes-cookbook)  
  
- [Distributions and Recipes](https://www.drupal.org/project/distributions_recipes)  
  
- [Repository](https://git.drupalcode.org/project/distributions_recipes/-/blob/1.0.x/docs/recipe.md)

### Author

![Reuben Walker headshot](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s8uaufe52fpxvz1qdcyr.jpg)
Reuben Walker

Founder
Symfony Station