symfony/recipes turns package configuration into a manifest
Symfony Recipes Repository
At a glance
- What is it?
- The Symfony recipes repository holds the official manifests that let Symfony Flex configure a Composer package when it is installed, so that requiring a bundle produces a configured application instead of a TODO. A recipe is a manifest.json file plus optional files, stored under a vendor/package/version/ directory structure, and the tasks it can perform are called configurators, from bundles and container parameters to environment variables, file copies, Makefile entries and Docker files.
- Who is it for?
- The Symfony recipes repository is the right thing to look at if you ship a PHP package that needs configuration, because the manifest format lets the package describe that configuration once and have Flex apply it, and reverse it, on every install.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.
Star history
- symfony/recipes1,029 ★ · +0
| Repository | 2026-10-21 | 2026-11-07 |
|---|---|---|
| symfony/recipes | 1k | 1k |
0 Stars in the last 17 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
A package that configures the packages around it
Symfony recipes allow the automation of Composer packages configuration via the Symfony Flex Composer plugin, and this repository contains the official recipes for Composer packages endorsed by the Symfony Core Team, with contributed recipes living in a separate contrib repository. The mechanism is the interesting part. Normally, requiring a library gives you the library and nothing else, and the configuration is a file you write by hand or copy from documentation, which is where new projects get their drift. A recipe inverts that, so that the dependency describes what should happen to the application when it is installed. The tasks are reversible, because Symfony is smart enough to reverse them when uninstalling and unconfiguring a dependency, which is what makes the feature safe to use on a live project. The audience is the package author who wants a new dependency to be usable the moment it is required, and the developer who wants the same setup every time.
The directory structure is a version, not a branch
Recipes consist of a manifest.json config file and, optionally, any number of files and directories, and they must be stored on their own repositories, outside of your Composer package repository. They must follow the vendor/package/version/ directory structure, where version is the minimum version supported by the recipe. The example in the README shows the real shape of it, with a console recipe at 3.3 holding a bin/ directory and a manifest.json, a framework-bundle recipe at 3.3 holding config/, public/ and src/ directories and a manifest.json, and a requirements-checker recipe at 1.0 holding only a manifest.json. The version directory is what makes upgrades work, since a newer version of a dependency can ship a newer directory of the same recipe and Flex will use the newest one the installed version supports. The manifest contents are optional, and they are divided into options and configurators, which are the two halves of the format.
Fifteen configurators, and options on top
Recipes define the tasks executed when installing a dependency, such as running commands, copying files or adding new environment variables, and they only contain the tasks needed to install and configure the dependency, because the reverse tasks are handled for you. The configurator types are bundles, container, copy-from-recipe, copy-from-package, env, dotenv, makefile, composer-scripts, composer-commands, gitignore, dockerfile, docker-compose, add-lines and post-install-output. The options are a separate layer on top, and the one documented in the README is aliases, which is not available in the recipes-contrib repository, and defines one or more alternative names that can be used to install the dependency, its value being an array of strings. So a dependency published as acme-inc/acme-log-monolog-handler can define aliases and then developers install it with composer require acme-log. That is a small feature with a large effect, because the alias becomes the name people type.
The bundles configurator, and what it writes
The bundles configurator enables one or more bundles in the Symfony application by appending them to the bundles.php file. Its value is an associative array where the key is the bundle class name and the value is an array of environments where it must be enabled, and the supported environments are dev, prod, test and all, where all enables the bundle in every environment:
{
"bundles": {
"Symfony\\Bundle\\DebugBundle\\DebugBundle": ["dev", "test"],
"Symfony\\Bundle\\MonologBundle\\MonologBundle": ["all"]
}
}The previous recipe is transformed into PHP in the config directory:
// config/bundles.php
return [
'Symfony\Bundle\DebugBundle\DebugBundle' => ['dev' => true, 'test' => true],
'Symfony\Bundle\MonologBundle\MonologBundle' => ['all' => true],
];The container configurator works the same way for parameters, adding them to services.yaml, for example a locale parameter with a default value of en. The notes in the README are the guidance for authors, and they are strict on purpose, do not create a recipe for a Symfony bundle if the only configuration in the manifest is the registration of the bundle for all environments, as that is done automatically, and do not create bundle configuration files under config/packages/ when no options are set.
Placeholders, and why hardcoded paths are forbidden
File copying uses placeholders, and the rule is that recipes must use them instead of hardcoding paths to be truly reusable. The copy-from-package configurator is an associative array where the key is the original file or directory and the value is the target, for example copying the bin/check.php script of the package into the binary directory of the application. The available placeholders are %BIN_DIR%, %CONF_DIR%, %CONFIG_DIR%, %SRC_DIR%, %VAR_DIR% and %PUBLIC_DIR%, and the placeholder values can be overridden in the extra section of your composer.json, where you can define your own as well:
// composer.json
{
"...": "...",
"extra": {
// overriding the value of the default placeholders
"bin-dir": "bin/",
"config-dir": "config/",
"src-dir": "src/",
"var-dir": "var/",
"public-dir": "public/",
// defining a custom placeholder (can be accessed using
// %MY_SPECIAL_DIR% in the recipe)
"my-special-dir": "..."
}
}The copy-from-recipe configurator is identical except that the contents come from the recipe itself rather than from the Composer package, and it is the one you use to ship the initial configuration of a dependency and a simple initial structure of files and directories. The caution attached to copy-from-package is the sharpest warning in the document, that copying files from the package should be avoided except for very specific use cases, and that copying PHP files under the project's src/ directory is almost always a bad idea, with the alternative being a command in your bundle that generates such files.
The rule that a recipe only changes for a bug
Updating recipes has a policy that is worth quoting because it explains the shape of the repository. When a recipe needs to be updated, the goal is to minimize the impact for the current versions, and creating a new project with a set of dependencies should always use the same recipes, to avoid differences between the generated code and the existing documentation, blog posts and videos for those versions. The rule of thumb is to follow the same principles as semantic versioning. Only change an existing recipe for a version in the case of a bug, such as typos or a mis-configuration. If the change is about a new best practice or a different way of doing something, do it for the next version of the dependency. That is a strict policy, and it is the reason the version directories in the repository look the way they do, since a recipe for 3.3 is effectively frozen and a new way of doing things appears in a 4.x directory.
Twenty-five vendors in one repository
The repository root is a directory per vendor, and the list is a good picture of the PHP ecosystem it serves: api-platform, blackfireio, doctrine, easycorp, friendsofphp, hautelook, javiereguiluz, league, lexik, nelmio, nyholm, php-cs-fixer, php-http, phpunit, scheb, sensio, sensiolabs, symfony, symfonycasts, symfonycorp, theofidry, twig, willdurand and zenstruck. The symfony/ directory holds the recipes for the framework's own packages, and each of those follows the vendor/package/version/ structure with a 3.3 directory in the example, which tells you which Symfony version the recipe targets. The repository is licensed MIT with a LICENSE file at the root, the default branch is main, the last push was on 2026-10-14, and there are no GitHub releases, which is consistent with a repository whose version history lives in the directory names and in the packages themselves rather than in tags.
Editorial conclusion
The Symfony recipes repository is the right thing to look at if you ship a PHP package that needs configuration, because the manifest format lets the package describe that configuration once and have Flex apply it, and reverse it, on every install. It is the wrong thing to reach for if your package needs a decision from the developer rather than a default, since a recipe can only apply the options it is given, and the note about not creating bundle configuration when no options are set is there because the automatic path is better. Before you write a recipe, read the versioning rules, since changing an existing recipe changes what a new project generates, and read the copy-from-package caution, since copying PHP into a project's src/ directory is almost always the wrong answer.
Frequently asked questions
What is a Symfony recipe?
A manifest.json file plus, optionally, files and directories, stored on its own repository under a vendor/package/version/ structure where version is the minimum supported version. Flex applies the manifest's tasks when the dependency is installed, and reverses them when it is uninstalled.
Which tasks can a recipe perform?
The configurator types are bundles, container, copy-from-recipe, copy-from-package, env, dotenv, makefile, composer-scripts, composer-commands, gitignore, dockerfile, docker-compose, add-lines and post-install-output. Above them sit options such as aliases, which define alternative package names to install.
When may an existing recipe be changed?
Only for a bug, such as a typo or a mis-configuration, and the rule of thumb is to follow semantic versioning principles. A change that reflects a new best practice or a different way of doing something belongs in the next version of the dependency, so that a new project still generates the same code as the existing documentation and videos for the current versions.
Why should a recipe avoid copying PHP files into src/?
The README cautions that copying files from the package should be avoided except for very specific use cases, and that copying PHP files under the project's src/ directory is almost always a bad idea. The alternative is to add a command in your bundle that is able to generate such PHP files instead.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/symfony-recipes)Star history chart for your README
[](https://hysenlabs.com/projects/symfony-recipes)Was this useful?