Facebook's Chef cookbooks model configuration as cascading hashes, not resources
Open source chef cookbooks.
At a glance
- What is it?
- chef-cookbooks is Facebook's set of attribute-driven Chef cookbooks, where services are configured through node attributes arranged in hashes and arrays, and the run-list is ordered least specific to most specific so that a site, a region or a single application can override anything above it. It suits infrastructure teams that want configuration to cascade and to be removable, and it assumes a delegate model of ownership that most Chef installations do not have.
- Who is it for?
- Infrastructure teams that already work in a delegate model, with a core team owning the base configuration and service teams overriding it, are the people these cookbooks were written for, and the cascade behaviour they give up is a genuine feature rather than an accident.
- Can I use it commercially?
- Yes. Apache-2.0 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 last received commits 15 days ago.
- What is it written in?
- Mainly Ruby, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The node object is the API, and that is the unusual part
Most Chef cookbooks expose resources as their interface, and Facebook's set does not. The documentation states it directly: unlike other cookbook models, we do not use resources as APIs, we use the node object, and configuration is modeled in arrays and hashes as closely and thinly as possible to the service being configured. The stated ideal is that you should only have to read the docs to the service to configure it, not the docs to the cookbook. The example is a service with a key-value configuration file, where the cookbook provides a simple hash and the keys and values go straight into the file. That is a thinner layer than a resource, and it means the shape of your configuration file is the shape of your cookbook attribute, with no translation layer in between. For a team that reads the upstream service documentation anyway, that is a meaningful reduction in what they have to learn.
Cascading configuration is the reason resources are avoided
The first of the two stated reasons for the attribute-driven design is cascading configuration, and the reasoning is concrete. The cookbooks are ordered least specific, owned by the core team that owns Chef, to most specific, owned by the team that owns the machine or service, so the team that cares about a specific instance can always override anything. The documentation gives a layered example, where a run-list contains core cookbooks, then site or company cookbooks, then region cookbooks for overrides for a given region or cluster, then application category cookbooks such as webserver or mail server, and finally a specific application cookbook. The example scenario is a shared memory setting that is shrunk for a region with different machine sizes, then changed again for web servers, then again for one internal webserver, and the documentation's conclusion is that this all just works. The contrast with resources is the sharp part, because using resources creates fighting instead, and the cron example is concrete: if you set up an hourly job with the cron resource and then someone else creates a cron for the same job at twice a day, each Chef run modifies the job to hourly and then re-modifies it to twice a day.
Idempotent systems, not idempotent settings, changes what removal means
The second reason is about what happens when you stop managing something, and it is the part most teams do not think about until it has already bitten them. The distinction is between what the documentation calls idempotent systems and idempotent settings, and the rule is that if you manage a specific item in a larger config and then stop managing it, it should either revert to a less specific setting or be removed, as necessary. The cron example again, but now about deletion. If you use the internal cron resource and then delete the recipe code that adds that cron job, that cron is not removed from your production environment, because it is on all existing nodes but on no new nodes, which is the kind of drift that is invisible until a new machine is provisioned. The workaround the model uses is templates that take over a whole configuration wherever possible. All cron jobs in the fb_cron API are written to /etc/cron.d/fb_crontab, and since the entries are just entries in a hash, deleting the lines that add a cron job means the cron disappears when the template is regenerated on the next run. A sysctl set by the site cookbook and then overwritten by a later cookbook behaves the same way, falling back to the next most specific value when the later code is removed.
Run-lists are short on purpose, and fb_init does the heavy lifting
The run-list section says how you formulate run-lists is up to your site, as long as you follow the basic rule that core cookbooks come first and you order least specific to most specific. At Facebook, all of their run-lists are one line.
recipe[fb_init], recipe[$SERVICE]The idea behind the line is stated plainly. fb_init should make you a Facebook server, and the rest should make you a whatever-kind-of-server-you-are, where fb_init is similar to the sample provided in this repository but with extra core cookbooks. So a run-list does not enumerate what to install, it names a service and lets the service cookbook pull in what it needs through the attribute cascade. Getting started is correspondingly simple on paper: grab a copy of the repository, rename fb_init_sample to fb_init, and follow the instructions in that cookbook's README, with coordinating guidance in comments in the default recipe. What is not simple is the coordination, since the comments in the default recipe are where the ordering rules are written down for the person configuring the run-list.
fb_ prefix, no environments, and versions that never change
Two conventions matter for anyone integrating these cookbooks. The first is the prefix, since cookbooks in this repository all begin with fb_ to denote both that they use the Facebook Cookbook Model and that they are maintained in this repository, and the documentation is explicit that local cookbooks or cookbooks in other repositories that implement the model should not use the prefix but should reference the document in their docs. The second is the run-from-main assumption. At Facebook, Grocery Delivery is used to sync the main branch of the source control repository with all of the Chef servers, and while Grocery Delivery is not necessary to use these cookbooks, they were built with that model in mind, so the versions never change, and the documentation notes the related fact that environments are not used at all. The point for a user is that there is no version negotiation to do, and equally no way to pin.
Taste Tester and Line Cook are the two tools around the cookbooks
The surrounding tooling is as much of the model as the cookbooks themselves. The testing assumption is a toolset that allows anyone modifying later cookbooks to ensure their use of the API worked as expected on a live node before committing, and Facebook uses Taste Tester for this. That is a real cost of the model, because it means a cookbook that changes behaviour on a node has to be validated against a live node rather than a test instance, and that is a step a smaller team will find awkward to reproduce. The update tooling is Line Cook, which the documentation highly recommends for syncing the cookbooks into your own repository so that you can pull in updates and fixes, described as like Dependabot but for Facebook style Chef cookbooks, and it supports UNIVERSE repos as well. The repository also carries UNIVERSE.md, which is the companion document for publishing your own cookbooks in that model, along with a.sugarjar.yaml file.
The repository is the tooling as much as the cookbooks
The top level of the tree explains how much of the effort is infrastructure rather than recipes. Alongside the cookbooks directory there is a cookstyle directory and three separate style configuration files,.cookstyle.yml,.cookstyle_combined.yml and.rubocop.yml, which suggests the style rules are applied per cookbook and then in combination across the set. There is a.mdl.style and.mdlrc pair for markdown linting, an.editorconfig, a Gemfile, a chefignore file and a scripts directory. Testing is configured through.kitchen.yml and.kitchen.vagrant.yml, with a TESTING.md documenting it and a spec directory for unit tests. There is a docs directory, a community_meetings directory, a CODE_OF_CONDUCT.md and a CONTRIBUTING.md. A continuous integration badge sits at the top of the readme, pointing at a ci.yml workflow. So a team that wants to contribute to this collection is not just adding a cookbook, they are participating in a shared tooling and style conversation.
Where the Facebook cookbook model is the wrong choice
The first wrong case is an installation with one team and one set of machines. The whole cascade is built for a situation with at least three layers of ownership, a core team, a site team and a service team, and if there is only one team then the layering is ceremony that adds run-list complexity for no override behaviour. The second wrong case is a service whose configuration is one entry inside a file that other things also manage, because the model explicitly manages whole files by template wherever possible, so an environment where something else writes to the same file is a conflict. The third wrong case is a team that wants a stable version to pin, since these cookbooks assume a run-from-main model in which the versions never change, and that assumption is incompatible with a change control process that requires knowing exactly which cookbook revision ran on a given node. The fourth is a team without the testing discipline, because Taste Tester validates a change against a live node before committing and there is no shortcut in the model for skipping that. The fifth is a project that needs a cookbook for a service Facebook does not run, since the repository only holds what Facebook maintains and anything else has to be written from scratch in the model.
Editorial conclusion
Infrastructure teams that already work in a delegate model, with a core team owning the base configuration and service teams overriding it, are the people these cookbooks were written for, and the cascade behaviour they give up is a genuine feature rather than an accident. It is the wrong choice for a single-team Chef installation, where nobody will ever write a region cookbook that overrides a site cookbook, and it is the wrong choice for a team that wants to manage one item inside a larger configuration file, since the model here manages whole files by template. Check three things before adopting the model: that you can actually order your run-lists least specific to most specific and keep them that way, that you are willing to sync cookbook updates into your own repository with the Line Cook bot rather than pinning a version, and that the services you need exist as fb_ prefixed cookbooks here, since the repository only holds what Facebook maintains. The licence is Apache-2.0, the last push was on 2026-10-08, and the repository publishes no GitHub releases.
Frequently asked questions
Why do Facebook's Chef cookbooks use node attributes instead of resources?
Two reasons, both documented. Attribute-driven APIs allow cascading configuration, so a run-list ordered least specific to most specific lets a later cookbook override an earlier one, and they give what the documentation calls idempotent systems rather than idempotent settings, meaning a setting you stop managing reverts or is removed rather than lingering on existing nodes.
What should a run-list look like when using facebook/chef-cookbooks?
Core cookbooks first, then least specific to most specific. At Facebook every run-list is recipe[fb_init], recipe[$SERVICE], where fb_init makes the machine a Facebook server and the service recipe then makes it the kind of server it is.
How do I get started with facebook/chef-cookbooks?
Grab a copy of the repository, rename fb_init_sample to fb_init, and follow the instructions in that cookbook's README, where coordinating guidance is in comments in the default recipe. The repository also recommends the Line Cook bot for syncing cookbook updates into your own repository.
What does the fb_ prefix mean on these cookbooks?
It marks both that the cookbook uses the Facebook Cookbook Model and that it is maintained in the facebook/chef-cookbooks repository. Local or third-party cookbooks that implement the same model should not use the prefix, and should reference the model document in their documentation instead.
How are changes to a Facebook cookbook tested?
The model assumes a testing toolset that lets anyone modifying later cookbooks check their use of the API worked as expected on a live node before committing, and Facebook uses Taste Tester for this.
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/facebook-chef-cookbooks)Was this useful?