{"id":418,"date":"2026-10-14T06:31:09","date_gmt":"2026-10-14T06:31:09","guid":{"rendered":"http:\/\/www.scmgalaxy.com\/tutorials\/2015\/08\/18\/know-about-metadata-rb-and-metadata-json-in-chef\/"},"modified":"2026-10-14T06:31:09","modified_gmt":"2026-10-14T06:31:09","slug":"know-about-metadata-rb-and-metadata-json-in-chef","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/know-about-metadata-rb-and-metadata-json-in-chef\/","title":{"rendered":"Chef Cookbook Metadata Explained: metadata.rb vs metadata.json"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Chef cookbook metadata lets Chef understand a cookbook\u2019s identity, version, dependencies, and platform support without evaluating every file in the cookbook. This guide is for DevOps engineers maintaining Chef cookbooks who want a clear, practical model of how <code>metadata.rb<\/code> and <code>metadata.json<\/code> are used.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Originally published on 2015-08-18; fully revised and updated.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This revision expands the original article from <a href=\"https:\/\/www.devopsschool.com\/blog\/know-about-metadata-rb-and-metadata-json-in-chef\/\">DevOpsSchool<\/a> with a clearer operational workflow and command-focused examples.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What metadata does in a Chef cookbook<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">In Chef, metadata provides machine-readable information about a cookbook so tooling and the Chef Server can reason about it correctly. Instead of parsing all cookbook files to infer behavior, Chef uses metadata to quickly determine compatibility and dependency requirements.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Cookbook identity (name, version, description)<\/li><li>Dependency declarations (for example, other cookbooks required)<\/li><li>Platform support and version constraints<\/li><li>Chef version compatibility and related hints for deployment<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">metadata.rb is the editable source of truth<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Every cookbook includes a <code>metadata.rb<\/code> file at the top level. This is the file you are expected to edit for permanent metadata changes. The original post also notes that <code>knife cookbook create<\/code> generates this file when scaffolding a new cookbook.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript language-ruby\">name <span class=\"hljs-string\">'my_cookbook'<\/span>\nmaintainer <span class=\"hljs-string\">'Platform Team'<\/span>\nmaintainer_email <span class=\"hljs-string\">'platform@example.com'<\/span>\nlicense <span class=\"hljs-string\">'Apache-2.0'<\/span>\ndescription <span class=\"hljs-string\">'Installs and configures my application'<\/span>\nversion <span class=\"hljs-string\">'1.2.3'<\/span>\nchef_version <span class=\"hljs-string\">'&gt;= 16.0'<\/span>\nsupports <span class=\"hljs-string\">'ubuntu'<\/span>, <span class=\"hljs-string\">'&gt;= 20.04'<\/span>\ndepends <span class=\"hljs-string\">'apt'<\/span>\ndepends <span class=\"hljs-string\">'nginx'<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">How metadata.json is generated and used<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><code>metadata.json<\/code> is generated from <code>metadata.rb<\/code>. As described in the original content, metadata is compiled when a cookbook is uploaded or when you run the metadata subcommand. You can edit <code>metadata.json<\/code> directly for temporary changes, but regeneration or upload can overwrite it.<\/p>\n\n\n\n<pre class=\"mermaid\">\nflowchart TD\n    A[Create cookbook] --> B[Edit metadata.rb]\n    B --> C[Run knife cookbook metadata]\n    C --> D[metadata.json written locally]\n    B --> E[Run knife cookbook upload]\n    E --> F[Chef compiles metadata from metadata.rb]\n    F --> G[Cookbook metadata stored on Chef Server]\n<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">metadata.rb vs metadata.json at a glance<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Aspect<\/th><th>metadata.rb<\/th><th>metadata.json<\/th><\/tr><\/thead><tbody><tr><td>Purpose<\/td><td>Human-edited cookbook metadata definition<\/td><td>Generated JSON representation of cookbook metadata<\/td><\/tr><tr><td>How it is created<\/td><td>Typically scaffolded by <code>knife cookbook create<\/code>, then edited manually<\/td><td>Generated from <code>metadata.rb<\/code> (for example via <code>knife cookbook metadata<\/code>)<\/td><\/tr><tr><td>Where to make permanent changes<\/td><td>Yes, this is the preferred location<\/td><td>No, direct edits are temporary and may be overwritten<\/td><\/tr><tr><td>Precedence when both files exist<\/td><td>Preferred at cookbook load time (per original source)<\/td><td>Not preferred when <code>metadata.rb<\/code> is present<\/td><\/tr><tr><td>Behavior during upload<\/td><td>Used as input for compiled metadata<\/td><td>Not the primary source in the classic <code>knife cookbook upload<\/code> flow<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Common knife commands for metadata workflows<\/h2>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php language-bash\"><span class=\"hljs-comment\"># Create a new cookbook (includes metadata.rb)<\/span>\nknife cookbook create my-cookbook\n\n<span class=\"hljs-comment\"># Generate or regenerate metadata.json from metadata.rb<\/span>\nknife cookbook metadata my-cookbook -o &lt;COOKBOOK_PATH&gt;\n\n<span class=\"hljs-comment\"># Example from the original article<\/span>\nknife cookbook metadata my-cookbook-name -o \/opt\/development\/cookbooks\/\n\n<span class=\"hljs-comment\"># Upload cookbook; metadata is compiled from metadata.rb<\/span>\nknife cookbook upload my-cookbook-name -o \/opt\/development\/cookbooks\/<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">When both files are present in a cookbook<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If both <code>metadata.rb<\/code> and <code>metadata.json<\/code> are present, the original source states that <code>metadata.rb<\/code> is preferred at load time. Operationally, this means you should treat <code>metadata.rb<\/code> as canonical and use <code>metadata.json<\/code> as a generated artifact.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Best practices<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li>Keep <code>metadata.rb<\/code> as the single source of truth for permanent metadata updates.<\/li><li>Regenerate metadata via tooling instead of hand-editing generated JSON.<\/li><li>Commit intentional metadata changes with version bumps and clear change history.<\/li><li>Validate dependency and platform constraints before upload.<\/li><li>Re-check command behavior against the Chef version used in your environment.<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Understand how Chef uses cookbook metadata, when metadata.json is generated, and why metadata.rb should be your source of truth. Includes workflow, command examples, and precedence rules when both files exist.<\/p>\n","protected":false},"author":1,"featured_media":3446,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[88],"tags":[407,1659,604,602,1050,1653,1654,1656,1655,670,1658,1657],"class_list":["post-418","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-chef","tag-chef","tag-chef-cookbooks","tag-chef-guide","tag-chef-tutorials","tag-cookbooks","tag-metadata","tag-metadata-in-chef","tag-metadata-json","tag-metadata-rb","tag-what","tag-what-is-metadata-json","tag-what-is-metadata-rb"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/418","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=418"}],"version-history":[{"count":4,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/418\/revisions"}],"predecessor-version":[{"id":79291,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/418\/revisions\/79291"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/3446"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=418"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=418"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=418"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}