{"id":1457,"date":"2025-11-04T11:24:03","date_gmt":"2025-11-04T10:24:03","guid":{"rendered":"https:\/\/deepdocs.dev\/?p=1457"},"modified":"2025-11-04T11:24:05","modified_gmt":"2025-11-04T10:24:05","slug":"json-schema-additionalproperties","status":"publish","type":"post","link":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/","title":{"rendered":"Mastering JSON Schema additionalProperties for Flexible Validation"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">In JSON Schema, the <code>additionalProperties<\/code> keyword acts as a gatekeeper for your data structures. In my experience, getting a handle on this one is critical. It&#8217;s the key to building APIs that are flexible enough to evolve but strict enough to shut down bad data before it gets in.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"tl-dr-key-takeaways\">TL;DR: Key Takeaways<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>additionalProperties<\/code> controls unknown fields<\/strong>: It defines validation rules for properties not listed in <code>properties<\/code> or matched by <code>patternProperties<\/code>.<\/li>\n\n\n\n<li><strong>Three modes of operation<\/strong>: It can be set to <code>true<\/code> (allow anything, the default), <code>false<\/code> (forbid anything extra), or a sub-schema (enforce specific rules on extra fields).<\/li>\n\n\n\n<li><strong>Default is permissive (<code>true<\/code>)<\/strong>: By default, JSON Schema allows any extra properties. This is a deliberate design choice for forward compatibility, but it often surprises developers.<\/li>\n\n\n\n<li><strong>Use <code>false<\/code> for strict inputs<\/strong>: Setting <code>additionalProperties: false<\/code> on API request bodies is a best practice for security, preventing mass assignment vulnerabilities.<\/li>\n\n\n\n<li><strong>Use sub-schemas for controlled flexibility<\/strong>: When you need to allow dynamic keys but enforce a consistent value structure (like for metadata or tags), using a schema for <code>additionalProperties<\/code> is the best approach.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"table-of-contents\">Table of Contents<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#what-are-additionalproperties-in-json-schema\">What Are additionalProperties in JSON Schema?<\/a><\/li>\n\n\n\n<li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#the-default-behavior-permissive-by-design\">The Default Behavior: Permissive by Design<\/a><\/li>\n\n\n\n<li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#enforcing-strict-contracts-with-additionalproperties-false\">Enforcing Strict Contracts with additionalProperties: false<\/a><\/li>\n\n\n\n<li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#the-advanced-pattern-using-a-sub-schema\">The Advanced Pattern: Using a Sub-Schema<\/a><\/li>\n\n\n\n<li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#how-additionalproperties-interacts-with-other-keywords\">How additionalProperties Interacts with Other Keywords<\/a><\/li>\n\n\n\n<li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#common-pitfalls-and-best-practices\">Common Pitfalls and Best Practices<\/a><\/li>\n\n\n\n<li><a class=\"wp-block-table-of-contents__entry\" href=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#common-questions-and-sticking-points\">Common Questions and Sticking Points<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-are-additionalproperties-in-json-schema\">What Are additionalProperties in JSON Schema?<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Imagine you\u2019re designing an API for a user profile. You start by defining the essentials, like <code>username<\/code> and <code>email<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But what happens down the road when a new feature needs to add a <code>lastLogin<\/code> field? Or, what if a client suddenly starts sending an unexpected <code>isAdmin<\/code> property?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This is exactly the problem <code>additionalProperties<\/code> was designed to solve. It sets the rules for any of these unplanned, &#8220;additional&#8221; properties that aren&#8217;t part of your original blueprint.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/jsoneditoronline.org\/_astro\/json-schema-validator.1GIn_IxH_GGDbt.svg\" alt=\"JSON Schema validator\" style=\"aspect-ratio:2.013845185651353;width:949px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Think of it as a switch with three settings. The setting you choose directly impacts how strict or forgiving your API is, making it one of the most important keywords you&#8217;ll need to master.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"the-three-modes-of-operation\">The Three Modes of Operation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">At a high level, <code>additionalProperties<\/code> gives you three distinct ways to control your object&#8217;s structure:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Permissive (<code>true<\/code>)<\/strong>: This is the default. It says, &#8220;anything goes,&#8221; allowing any number of extra properties. This mode is great for systems where new fields might be added over time without breaking older clients.<\/li>\n\n\n\n<li><strong>Strict (<code>false<\/code>)<\/strong>: This setting locks the object down completely. Only properties you\u2019ve explicitly defined in <code>properties<\/code> or <code>patternProperties<\/code> are allowed. It\u2019s perfect for security-sensitive endpoints where you need absolute certainty about the data&#8217;s shape.<\/li>\n\n\n\n<li><strong>Conditional (Schema)<\/strong>: This offers a powerful middle ground. You provide another schema that all additional properties must conform to. For example, you could require all extra fields to be strings.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Understanding these three options is the first step toward creating robust and predictable APIs. Choosing the right mode from the start prevents countless validation headaches down the line.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-default-behavior-permissive-by-design\">The Default Behavior: Permissive by Design<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One of the first things that trips up developers new to <a href=\"https:\/\/json-schema.org\/\">JSON Schema<\/a> is its default behavior. It\u2019s surprisingly\u2026 relaxed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you don\u2019t explicitly say anything about extra properties, it lets them slide right through. In other words, <code>additionalProperties<\/code> is implicitly set to <code>true<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This feels wrong at first, doesn&#8217;t it? But this permissive default is a deliberate design choice with a critical purpose: <strong>forward compatibility<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"a-feature-not-a-bug\">A Feature, Not a Bug<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s say you&#8217;re building an API that processes customer orders. Your first version of the schema might only need an <code>orderId<\/code> and an <code>amount<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"type\": \"object\",\n  \"properties\": {\n    \"orderId\": { \"type\": \"string\" },\n    \"amount\": { \"type\": \"number\" }\n  },\n  \"required\": &#91;\"orderId\", \"amount\"]\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now, imagine a client sends this JSON object, which includes an extra <code>promoCode<\/code> field.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"orderId\": \"ORD-12345\",\n  \"amount\": 99.99,\n  \"promoCode\": \"SAVE20\"\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Because our schema defaults to <code>additionalProperties: true<\/code>, the object above is <strong>perfectly valid<\/strong>. The validator checks <code>orderId<\/code> and <code>amount<\/code>, sees they&#8217;re correct, and simply ignores <code>promoCode<\/code>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">This flexibility is a lifesaver. It means you can evolve your API, adding new, optional fields, without breaking older clients.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">This design prevents your system from becoming brittle. If schemas were strict by default, every minor addition would be a breaking change, forcing a cascade of updates. The permissive nature of <code>additionalProperties<\/code> allows for graceful evolution, which is essential for maintainable systems.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"enforcing-strict-contracts-with-additionalproperties-false\">Enforcing Strict Contracts with additionalProperties: false<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">While the default is great for flexibility, sometimes you need the exact opposite. This is where setting <code>additionalProperties<\/code> to <strong><code>false<\/code><\/strong> becomes your most powerful tool.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">It transforms your schema from a guideline into a rigid blueprint. Only the properties you&#8217;ve explicitly defined are allowed. Period.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This setting slams the gate shut on unknown fields. If a client sends even one extra property, the entire object will fail validation.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"682\" data-attachment-id=\"1557\" data-permalink=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/image-96\/\" data-orig-file=\"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/image-39.png?fit=1400%2C933&amp;ssl=1\" data-orig-size=\"1400,933\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"image\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/image-39.png?fit=1024%2C682&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/image-39.png?resize=1024%2C682&#038;ssl=1\" alt=\"\" class=\"wp-image-1557\" srcset=\"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/image-39.png?resize=1024%2C682&amp;ssl=1 1024w, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/image-39.png?resize=300%2C200&amp;ssl=1 300w, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/image-39.png?resize=768%2C512&amp;ssl=1 768w, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/image-39.png?resize=1200%2C800&amp;ssl=1 1200w, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/image-39.png?w=1400&amp;ssl=1 1400w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"a-practical-example-of-strict-validation\">A Practical Example of Strict Validation<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s go back to our user profile schema, but this time, we&#8217;ll lock it down.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"$schema\": \"http:\/\/json-schema.org\/draft-07\/schema#\",\n  \"title\": \"Strict User Profile\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"username\": { \"type\": \"string\" },\n    \"email\": { \"type\": \"string\", \"format\": \"email\" }\n  },\n  \"required\": &#91;\"username\", \"email\"],\n  \"additionalProperties\": false\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now, imagine this JSON payload comes in:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"username\": \"testuser\",\n  \"email\": \"test@example.com\",\n  \"isAdmin\": true\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">With <strong><code>additionalProperties: false<\/code><\/strong> in place, this object is <strong>invalid<\/strong>. The <code>isAdmin<\/code> property isn&#8217;t defined, so the validator rejects the entire payload.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"when-to-enforce-strictness\">When to Enforce Strictness<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Deciding to set <code>additionalProperties<\/code> to <code>false<\/code> is a strategic choice. It\u2019s particularly useful in these scenarios:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Securing API Endpoints<\/strong>: By rejecting unknown properties, you can help shut down mass assignment vulnerabilities. You prevent a malicious user from injecting fields they shouldn&#8217;t have access to, like that sneaky <code>isAdmin<\/code> flag.<\/li>\n\n\n\n<li><strong>Defining Precise Configurations<\/strong>: For config files, strict validation ensures there are no typos or misunderstood options. An unknown property is an error, preventing silent failures.<\/li>\n\n\n\n<li><strong>High-Stakes Data Exchange<\/strong>: Think financial transactions or healthcare records. A strict schema ensures you process <em>exactly<\/em> what you expect, and nothing more.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">By default, JSON Schema is permissive, but a huge number of developers rely on <strong><code>additionalProperties: false<\/code><\/strong> to enforce data integrity. To see how these principles apply in the real world, check out our <a href=\"https:\/\/deepdocs.dev\/how-to-make-an-api\/\">guide on making a great API<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Of course, this approach has trade-offs. It makes your API less adaptable. The key is to find the right balance, applying strictness where security and precision are non-negotiable.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-advanced-pattern-using-a-sub-schema\">The Advanced Pattern: Using a Sub-Schema<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">So far, we\u2019ve treated <code>additionalProperties<\/code> as a simple on\/off switch. But its real power comes from using another schema as its value.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This pattern lets you define rules that all <em>extra<\/em> properties must follow. It\u2019s like telling a bouncer, &#8220;Anyone not on the main list is welcome, but they <em>must<\/em> all be wearing a blue shirt.&#8221;<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"defining-rules-for-extra-properties\">Defining Rules for Extra Properties<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s look at a practical example. Imagine a config file for a web app. We have core settings like <code>theme<\/code> and <code>timeout<\/code>, but we also want to let developers add custom metadata. We need to ensure all the metadata values are non-empty strings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s how we\u2019d write that schema:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"$schema\": \"http:\/\/json-schema.org\/draft-07\/schema#\",\n  \"title\": \"App Configuration with Metadata\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"theme\": { \"type\": \"string\", \"enum\": &#91;\"dark\", \"light\"] },\n    \"timeout\": { \"type\": \"integer\", \"minimum\": 0 }\n  },\n  \"required\": &#91;\"theme\", \"timeout\"],\n  \"additionalProperties\": {\n    \"type\": \"string\",\n    \"minLength\": 1\n  }\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In this schema, any property that <em>isn&#8217;t<\/em> <code>theme<\/code> or <code>timeout<\/code> will be checked against the sub-schema: <code>{ \"type\": \"string\", \"minLength\": 1 }<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s test a few objects:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>{ \"theme\": \"dark\", \"timeout\": 5000, \"author\": \"dev-team\" }<\/code> &#8211; <strong>Valid<\/strong>. <code>author<\/code> is an extra property, and its value is a non-empty string.<\/li>\n\n\n\n<li><code>{ \"theme\": \"light\", \"timeout\": 1000, \"version\": 1.2 }<\/code> &#8211; <strong>Invalid<\/strong>. The value <code>1.2<\/code> is a number, not a string.<\/li>\n\n\n\n<li><code>{ \"theme\": \"dark\", \"timeout\": 3000, \"note\": \"\" }<\/code> &#8211; <strong>Invalid<\/strong>. The value for <code>note<\/code> violates the <code>minLength: 1<\/code> constraint.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This technique gives you fine-grained control, ensuring even unplanned data follows a predictable structure.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"common-use-cases-for-sub-schemas\">Common Use Cases for Sub-Schemas<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This pattern is a lifesaver in many real-world scenarios. We&#8217;ve found it shines brightest when handling dynamic data without throwing validation out the window.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>User-Defined Metadata<\/strong>: Allowing users to attach custom key-value tags to resources (like AWS tags) is a classic example. You can enforce that all metadata values must be strings or numbers.<\/li>\n\n\n\n<li><strong>Plugin Architectures<\/strong>: For config files that support third-party plugins, you can define a schema for what a valid plugin configuration looks like and apply it to all non-core properties.<\/li>\n\n\n\n<li><strong>Key-Value Stores<\/strong>: If you&#8217;re building an API that functions like a key-value store, a sub-schema ensures every value conforms to a predefined structure, even though keys are dynamic.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"how-additionalproperties-interacts-with-other-keywords\">How additionalProperties Interacts with Other Keywords<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">When you mix <code>additionalProperties<\/code> with <code>properties<\/code> and <code>patternProperties<\/code>, its behavior gets more interesting.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The key takeaway is this: <strong><code>additionalProperties<\/code> only kicks in for properties that haven&#8217;t already been matched<\/strong> by <code>properties<\/code> or <code>patternProperties<\/code>. This creates a clean hierarchy for precise validation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"understanding-the-validation-order\">Understanding the Validation Order<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Picture your schema applying rules in three layers:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><code>properties<\/code><\/strong>: The validator first checks for specific, named keys like <code>\"id\"<\/code>. If a property name matches, this rule applies.<\/li>\n\n\n\n<li><strong><code>patternProperties<\/code><\/strong>: If a property wasn&#8217;t matched, the validator tries to match its name against regular expressions here. The first pattern that matches wins.<\/li>\n\n\n\n<li><strong><code>additionalProperties<\/code><\/strong>: This is the last resort. Only properties that slipped past the first two checks are handed off to <code>additionalProperties<\/code>.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">This behavior was clarified in Draft 7 of JSON Schema to avoid ambiguity. You can dive into the history in <a href=\"https:\/\/github.com\/orgs\/json-schema-org\/discussions\/57\">the official JSON Schema discussions<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"a-layered-validation-example\">A Layered Validation Example<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s define a user object. We need a couple of required fields, we want to allow custom fields that start with <code>data-<\/code>, but we want to forbid everything else.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here\u2019s the schema:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"$schema\": \"http:\/\/json-schema.org\/draft-07\/schema#\",\n  \"title\": \"User with Custom Data\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"userId\": { \"type\": \"string\" },\n    \"email\": { \"type\": \"string\", \"format\": \"email\" }\n  },\n  \"patternProperties\": {\n    \"^data-\": { \"type\": \"string\" }\n  },\n  \"required\": &#91;\"userId\", \"email\"],\n  \"additionalProperties\": false\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now, let&#8217;s test it:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><br><p><strong>Valid Data<\/strong>: <code>{ \"userId\": \"u-123\", \"email\": \"a@b.com\", \"data-team\": \"alpha\" }<\/code><br>This object is valid. <code>userId<\/code> and <code>email<\/code> are handled by <code>properties<\/code>. <code>data-team<\/code> matches the <code>^data-<\/code> regex. Nothing is left for <code>additionalProperties<\/code>.<\/p><br><\/li>\n\n\n\n<li><br><p><strong>Invalid Data<\/strong>: <code>{ \"userId\": \"u-456\", \"email\": \"c@d.com\", \"isAdmin\": true }<\/code><br>This fails. <code>isAdmin<\/code> doesn&#8217;t match anything in <code>properties<\/code> or <code>patternProperties<\/code>. It falls down to <code>additionalProperties: false<\/code> and is rejected.<\/p><br><\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Getting a handle on this hierarchy separates a basic schema from a robust one. For more hands-on designs, check out our <a href=\"https:\/\/deepdocs.dev\/open-api-examples\/\">OpenAPI examples<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"common-pitfalls-and-best-practices\">Common Pitfalls and Best Practices<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Like any powerful tool, <code>additionalProperties<\/code> can cause headaches if you&#8217;re not careful. I\u2019ve seen developers fall into a few common traps, like making APIs brittle or misunderstanding the default behavior.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One frequent mistake is jumping to <code>additionalProperties: false<\/code> on API responses. Sure, it feels strict, but it paints you into a corner. The moment you add a minor field in the future, you risk breaking every client that relies on that rigid schema.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><iframe width=\"100%\" style=\"aspect-ratio: 16 \/ 9;\" src=\"https:\/\/www.youtube.com\/embed\/SlnycdnKSaU\" frameborder=\"0\" allow=\"autoplay; encrypted-media\" allowfullscreen=\"\"><\/iframe><\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"avoiding-common-mistakes\">Avoiding Common Mistakes<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">To build schemas that last, it pays to follow a few principles.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Default to <code>false<\/code> for Request Bodies<\/strong>: When building an endpoint that accepts data, <code>additionalProperties: false<\/code> is a smart security move. It&#8217;s a great defense against mass assignment vulnerabilities.<\/li>\n\n\n\n<li><strong>Be Cautious with <code>false<\/code> in Responses<\/strong>: For data you send back, think twice before setting <code>additionalProperties: false<\/code>. Leaving it open means you can add new properties later without breaking older clients.<\/li>\n\n\n\n<li><strong>Use a Sub-Schema for Controlled Extensibility<\/strong>: A sub-schema is perfect for the middle ground. It lets you allow dynamic properties but still enforce rules, like making sure every value in a <code>metadata<\/code> object is a string.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/cdn.outrank.so\/c5154994-a2fe-43c0-a286-28e433de4fd1\/53ccd14a-f8c3-4a45-b9f9-1411d8cb6cac.jpg?ssl=1\" alt=\"Infographic about json schema additionalproperties\"\/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Caption: This diagram shows <code>additionalProperties<\/code> as the final check after <code>properties<\/code> and <code>patternProperties<\/code>.<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This visual drives home a key point: <code>additionalProperties<\/code> only applies to properties not covered by more specific rules.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"document-your-decisions\">Document Your Decisions<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Finally, don&#8217;t forget that clear communication is everything. The way you handle <code>additionalProperties<\/code> has real-world consequences, as seen in the tricky data transitions discussed in the <a href=\"https:\/\/github.com\/json-schema-org\/json-schema-spec\/issues\/661\">JSON Schema community<\/a>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">Always document your choice for <code>additionalProperties<\/code> and the reasoning behind it. Whether you&#8217;re aiming for strictness or flexibility, your API consumers need to know what to expect.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Good documentation elevates your schema from a simple validation file to a reliable contract. If you want to dig deeper, check out our guide on <a href=\"https:\/\/deepdocs.dev\/api-documentation-best-practices\/\">API documentation best practices<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"common-questions-and-sticking-points\">Common Questions and Sticking Points<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Even after you get the hang of <code>additionalProperties<\/code>, a few questions tend to pop up. Let&#8217;s walk through the most frequent ones.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"how-can-i-use-additionalproperties-to-ban-all-properties\">How Can I Use additionalProperties to Ban All Properties?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">On its own, <code>additionalProperties: false<\/code> only applies to <em>undefined<\/em> properties. To block <em>everything<\/em>, combine it with empty <code>properties<\/code> and <code>patternProperties<\/code> objects.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"type\": \"object\",\n  \"properties\": {},\n  \"patternProperties\": {},\n  \"additionalProperties\": false\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This setup tells the validator that there are no allowed named properties and no allowed patterns, so <em>any<\/em> property is considered &#8220;additional&#8221; and will be rejected. This is the go-to method for enforcing a truly empty object.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"how-do-i-make-a-property-optional\">How Do I Make a Property Optional?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">It&#8217;s easy to mix up <code>additionalProperties<\/code> with property optionality. <code>additionalProperties<\/code> handles <em>unknown<\/em> properties.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To make a <em>known<\/em> property optional, you use the <strong><code>required<\/code><\/strong> array. Define the property in your <code>properties<\/code> object but leave its name out of the <code>required<\/code> list.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For instance, to make <code>email<\/code> optional:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"type\": \"object\",\n  \"properties\": {\n    \"username\": { \"type\": \"string\" },\n    \"email\": { \"type\": \"string\" }\n  },\n  \"required\": &#91;\"username\"]\n}\n<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Here, <code>email<\/code> is valid, but an object will pass validation whether <code>email<\/code> is present or not.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"what-is-the-default-value-of-additionalproperties\">What Is the Default Value of additionalProperties?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is the single most important detail to remember: the default value for <strong><code>additionalProperties<\/code><\/strong> is <strong><code>true<\/code><\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">If you don&#8217;t explicitly add <code>additionalProperties: false<\/code>, JSON Schema will allow any extra properties. This was a deliberate choice to support forward compatibility, but it means you must be intentional about locking down your schemas when you need strict validation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Tired of your documentation drifting from your code? <strong>DeepDocs<\/strong> is a GitHub-native AI app that automatically detects outdated docs and keeps them in sync with every commit. It intelligently updates only what&#8217;s needed, preserving your style and formatting. Stop manual updates and ensure your READMEs, API references, and tutorials are always accurate. <a href=\"https:\/\/deepdocs.dev\">Get started for free at deepdocs.dev<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In JSON Schema, the additionalProperties keyword acts as a gatekeeper for your data structures. In my experience, getting a handle on this one is critical. It&#8217;s the key to building APIs that are flexible enough to evolve but strict enough to shut down bad data before it gets in. TL;DR: Key Takeaways Table of Contents&#8230;<\/p>\n","protected":false},"author":259061979,"featured_media":1549,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"{title}\n\n{excerpt}\n\n{url}","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[1390],"tags":[],"class_list":["post-1457","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-docs"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.8 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Mastering JSON Schema additionalProperties for Flexible Validation | DeepDocs<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Mastering JSON Schema additionalProperties for Flexible Validation | DeepDocs\" \/>\n<meta property=\"og:description\" content=\"In JSON Schema, the additionalProperties keyword acts as a gatekeeper for your data structures. In my experience, getting a handle on this one is critical. It&#8217;s the key to building APIs that are flexible enough to evolve but strict enough to shut down bad data before it gets in. TL;DR: Key Takeaways Table of Contents...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/\" \/>\n<meta property=\"og:site_name\" content=\"DeepDocs\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/profile.php?id=61560455754198\" \/>\n<meta property=\"article:published_time\" content=\"2025-11-04T10:24:03+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-04T10:24:05+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Neel Das\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@Nilzkool\" \/>\n<meta name=\"twitter:site\" content=\"@Nilzkool\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Neel Das\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/\"},\"author\":{\"name\":\"Neel Das\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#\\\/schema\\\/person\\\/cf2ace6ae4dae8b34ab48a3e833ceede\"},\"headline\":\"Mastering JSON Schema additionalProperties for Flexible Validation\",\"datePublished\":\"2025-11-04T10:24:03+00:00\",\"dateModified\":\"2025-11-04T10:24:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/\"},\"wordCount\":2066,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/10\\\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1\",\"articleSection\":[\"Docs\"],\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/\",\"url\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/\",\"name\":\"Mastering JSON Schema additionalProperties for Flexible Validation | DeepDocs\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/10\\\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1\",\"datePublished\":\"2025-11-04T10:24:03+00:00\",\"dateModified\":\"2025-11-04T10:24:05+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/10\\\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/10\\\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1\",\"width\":1920,\"height\":1080},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/json-schema-additionalproperties\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/deepdocs.dev\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Mastering JSON Schema additionalProperties for Flexible Validation\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#website\",\"url\":\"https:\\\/\\\/deepdocs.dev\\\/\",\"name\":\"DeepDocs\",\"description\":\"Fix Your Outdated GitHub Docs on Autopilot\",\"publisher\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/deepdocs.dev\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#organization\",\"name\":\"DeepDocs\",\"url\":\"https:\\\/\\\/deepdocs.dev\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/6.jpg?fit=408%2C400&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/deepdocs.dev\\\/wp-content\\\/uploads\\\/2025\\\/06\\\/6.jpg?fit=408%2C400&ssl=1\",\"width\":408,\"height\":400,\"caption\":\"DeepDocs\"},\"image\":{\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/profile.php?id=61560455754198\",\"https:\\\/\\\/x.com\\\/Nilzkool\",\"https:\\\/\\\/www.linkedin.com\\\/company\\\/deepdocs-dev\",\"https:\\\/\\\/www.youtube.com\\\/@DrNeelDas\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/deepdocs.dev\\\/#\\\/schema\\\/person\\\/cf2ace6ae4dae8b34ab48a3e833ceede\",\"name\":\"Neel Das\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/227924e7431a87895450dcd654b650e5011891dcba027fd9c782941985cbbb2d?s=96&d=identicon&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/227924e7431a87895450dcd654b650e5011891dcba027fd9c782941985cbbb2d?s=96&d=identicon&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/227924e7431a87895450dcd654b650e5011891dcba027fd9c782941985cbbb2d?s=96&d=identicon&r=g\",\"caption\":\"Neel Das\"},\"sameAs\":[\"http:\\\/\\\/neeldasf2ac55feaf.wordpress.com\"],\"url\":\"https:\\\/\\\/deepdocs.dev\\\/author\\\/neeldasf2ac55feaf\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Mastering JSON Schema additionalProperties for Flexible Validation | DeepDocs","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/","og_locale":"en_GB","og_type":"article","og_title":"Mastering JSON Schema additionalProperties for Flexible Validation | DeepDocs","og_description":"In JSON Schema, the additionalProperties keyword acts as a gatekeeper for your data structures. In my experience, getting a handle on this one is critical. It&#8217;s the key to building APIs that are flexible enough to evolve but strict enough to shut down bad data before it gets in. TL;DR: Key Takeaways Table of Contents...","og_url":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/","og_site_name":"DeepDocs","article_publisher":"https:\/\/www.facebook.com\/profile.php?id=61560455754198","article_published_time":"2025-11-04T10:24:03+00:00","article_modified_time":"2025-11-04T10:24:05+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg","type":"image\/jpeg"}],"author":"Neel Das","twitter_card":"summary_large_image","twitter_creator":"@Nilzkool","twitter_site":"@Nilzkool","twitter_misc":{"Written by":"Neel Das","Estimated reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#article","isPartOf":{"@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/"},"author":{"name":"Neel Das","@id":"https:\/\/deepdocs.dev\/#\/schema\/person\/cf2ace6ae4dae8b34ab48a3e833ceede"},"headline":"Mastering JSON Schema additionalProperties for Flexible Validation","datePublished":"2025-11-04T10:24:03+00:00","dateModified":"2025-11-04T10:24:05+00:00","mainEntityOfPage":{"@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/"},"wordCount":2066,"commentCount":0,"publisher":{"@id":"https:\/\/deepdocs.dev\/#organization"},"image":{"@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1","articleSection":["Docs"],"inLanguage":"en-GB","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/","url":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/","name":"Mastering JSON Schema additionalProperties for Flexible Validation | DeepDocs","isPartOf":{"@id":"https:\/\/deepdocs.dev\/#website"},"primaryImageOfPage":{"@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#primaryimage"},"image":{"@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1","datePublished":"2025-11-04T10:24:03+00:00","dateModified":"2025-11-04T10:24:05+00:00","breadcrumb":{"@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/deepdocs.dev\/json-schema-additionalproperties\/"]}]},{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#primaryimage","url":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1","contentUrl":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1","width":1920,"height":1080},{"@type":"BreadcrumbList","@id":"https:\/\/deepdocs.dev\/json-schema-additionalproperties\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/deepdocs.dev\/"},{"@type":"ListItem","position":2,"name":"Mastering JSON Schema additionalProperties for Flexible Validation"}]},{"@type":"WebSite","@id":"https:\/\/deepdocs.dev\/#website","url":"https:\/\/deepdocs.dev\/","name":"DeepDocs","description":"Fix Your Outdated GitHub Docs on Autopilot","publisher":{"@id":"https:\/\/deepdocs.dev\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/deepdocs.dev\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":"Organization","@id":"https:\/\/deepdocs.dev\/#organization","name":"DeepDocs","url":"https:\/\/deepdocs.dev\/","logo":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/deepdocs.dev\/#\/schema\/logo\/image\/","url":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/06\/6.jpg?fit=408%2C400&ssl=1","contentUrl":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/06\/6.jpg?fit=408%2C400&ssl=1","width":408,"height":400,"caption":"DeepDocs"},"image":{"@id":"https:\/\/deepdocs.dev\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/profile.php?id=61560455754198","https:\/\/x.com\/Nilzkool","https:\/\/www.linkedin.com\/company\/deepdocs-dev","https:\/\/www.youtube.com\/@DrNeelDas"]},{"@type":"Person","@id":"https:\/\/deepdocs.dev\/#\/schema\/person\/cf2ace6ae4dae8b34ab48a3e833ceede","name":"Neel Das","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/secure.gravatar.com\/avatar\/227924e7431a87895450dcd654b650e5011891dcba027fd9c782941985cbbb2d?s=96&d=identicon&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/227924e7431a87895450dcd654b650e5011891dcba027fd9c782941985cbbb2d?s=96&d=identicon&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/227924e7431a87895450dcd654b650e5011891dcba027fd9c782941985cbbb2d?s=96&d=identicon&r=g","caption":"Neel Das"},"sameAs":["http:\/\/neeldasf2ac55feaf.wordpress.com"],"url":"https:\/\/deepdocs.dev\/author\/neeldasf2ac55feaf\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/10\/Blue-Gradient-Modern-Sport-Presentation-1-5.jpg?fit=1920%2C1080&ssl=1","jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pgAtwt-nv","jetpack-related-posts":[{"id":2579,"url":"https:\/\/deepdocs.dev\/github-actions-inputs\/","url_meta":{"origin":1457,"position":0},"title":"A Developer&#8217;s Guide to GitHub Actions Inputs","author":"Emmanuel Mumba","date":"23 February 2026","format":false,"excerpt":"If you want to build flexible and reusable CI\/CD pipelines, you have to get comfortable with GitHub Actions inputs. They are the secret sauce for controlling your automation at runtime, letting you build powerful workflows without hardcoding values. In our experience, mastering inputs is what separates a brittle CI\/CD setup\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/deepdocs.dev\/category\/docs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/02\/github-actions-inputs-developer-guide-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/02\/github-actions-inputs-developer-guide-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/02\/github-actions-inputs-developer-guide-1.jpg?fit=1200%2C673&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/02\/github-actions-inputs-developer-guide-1.jpg?fit=1200%2C673&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/02\/github-actions-inputs-developer-guide-1.jpg?fit=1200%2C673&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":1610,"url":"https:\/\/deepdocs.dev\/rest-api-best-practices\/","url_meta":{"origin":1457,"position":1},"title":"10 Essential REST API Best Practices for Developers","author":"Emmanuel Mumba","date":"15 November 2025","format":false,"excerpt":"TL;DR: Key Takeaways Use Nouns for Resources: Structure your API endpoints around nouns (e.g., \/users), not verbs (\/getUsers). Let HTTP methods (GET, POST, PUT, DELETE) define the action. Leverage Proper HTTP Status Codes: Use specific codes like 201 Created for success, 400 Bad Request for client errors, and 500 Internal\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/deepdocs.dev\/category\/docs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/11\/jpg7.png?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/11\/jpg7.png?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/11\/jpg7.png?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/11\/jpg7.png?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/11\/jpg7.png?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":2042,"url":"https:\/\/deepdocs.dev\/configuration-files-python\/","url_meta":{"origin":1457,"position":2},"title":"Mastering Configuration Files in Python","author":"Emmanuel Mumba","date":"1 January 2026","format":false,"excerpt":"Configuration files are the unsung heroes of Python applications. They separate your logic from settings that change between environments, like database passwords or API keys. Getting this right makes your code portable, secure, and far easier to manage. TL;DR: Key Takeaways Separate Config from Code: Never hardcode settings. External configuration\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/deepdocs.dev\/category\/docs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/12\/configuration-files-python-config-essentials-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/12\/configuration-files-python-config-essentials-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/12\/configuration-files-python-config-essentials-1.jpg?fit=1200%2C673&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/12\/configuration-files-python-config-essentials-1.jpg?fit=1200%2C673&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2025\/12\/configuration-files-python-config-essentials-1.jpg?fit=1200%2C673&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":3667,"url":"https:\/\/deepdocs.dev\/software-design-document-format\/","url_meta":{"origin":1457,"position":3},"title":"Software Design Document Format: Your 2026 Guide","author":"Emmanuel Mumba","date":"1 June 2026","format":false,"excerpt":"You usually know the project is in trouble before anyone says it out loud. A new engineer asks how a service works, and the answer is a Slack thread, a stale diagram, and \u201cread the code.\u201d A dependency breaks in production, and nobody can tell whether the current behavior was\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/deepdocs.dev\/category\/docs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/06\/software-design-document-format-guide-title-1.jpg?fit=1200%2C675&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/06\/software-design-document-format-guide-title-1.jpg?fit=1200%2C675&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/06\/software-design-document-format-guide-title-1.jpg?fit=1200%2C675&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/06\/software-design-document-format-guide-title-1.jpg?fit=1200%2C675&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/06\/software-design-document-format-guide-title-1.jpg?fit=1200%2C675&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":3343,"url":"https:\/\/deepdocs.dev\/visualize-database-structure\/","url_meta":{"origin":1457,"position":4},"title":"Visualize Database Structure: Reverse Engineering &#038; ERDs","author":"Neel Das","date":"17 April 2026","format":false,"excerpt":"A database diagram usually gets created at the worst possible moment. A new engineer joins. A production issue touches five tables nobody fully understands. A migration lands, and someone asks whether it breaks reporting, billing, or auth. That\u2019s when teams realize they don\u2019t have a schema problem. They have a\u2026","rel":"","context":"In &quot;Docs&quot;","block_context":{"text":"Docs","link":"https:\/\/deepdocs.dev\/category\/docs\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/04\/visualize-database-structure-erd-diagrams-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/04\/visualize-database-structure-erd-diagrams-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/04\/visualize-database-structure-erd-diagrams-1.jpg?fit=1200%2C673&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/04\/visualize-database-structure-erd-diagrams-1.jpg?fit=1200%2C673&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/04\/visualize-database-structure-erd-diagrams-1.jpg?fit=1200%2C673&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":3423,"url":"https:\/\/deepdocs.dev\/ai-prompt-library\/","url_meta":{"origin":1457,"position":5},"title":"Build Your AI Prompt Library for Production Success","author":"Neel Das","date":"8 May 2026","format":false,"excerpt":"Teams usually adopt AI the same way they adopt shell aliases. One person finds something useful, shares it in chat, and three weeks later nobody remembers which exact wording produced the good result. The prompts drift, the outputs drift, and soon the team is arguing about model quality when the\u2026","rel":"","context":"Similar post","block_context":{"text":"Similar post","link":""},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/05\/ai-prompt-library-illustration-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/05\/ai-prompt-library-illustration-1.jpg?fit=1200%2C673&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/05\/ai-prompt-library-illustration-1.jpg?fit=1200%2C673&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/05\/ai-prompt-library-illustration-1.jpg?fit=1200%2C673&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/deepdocs.dev\/wp-content\/uploads\/2026\/05\/ai-prompt-library-illustration-1.jpg?fit=1200%2C673&ssl=1&resize=1050%2C600 3x"},"classes":[]}],"_links":{"self":[{"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/posts\/1457","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/users\/259061979"}],"replies":[{"embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/comments?post=1457"}],"version-history":[{"count":5,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/posts\/1457\/revisions"}],"predecessor-version":[{"id":1560,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/posts\/1457\/revisions\/1560"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/media\/1549"}],"wp:attachment":[{"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/media?parent=1457"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/categories?post=1457"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/deepdocs.dev\/wp-json\/wp\/v2\/tags?post=1457"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}