How to Use OpenAPI Overlays

How to Use OpenAPI Overlays #

The OpenAPI Overlay Specification provides a structured way to apply changes to an OpenAPI document without touching the original file. Instead of maintaining several diverging copies of the same document for different audiences or environments, you maintain one canonical OpenAPI description and one or more overlay files that describe the differences. This guide walks through every option available in an overlay document and shows a working example for each.

For background on why overlays exist and the problems they solve, see What is the OpenAPI Overlay Specification?.

The Building Blocks of an Overlay Document #

An overlay document is a YAML or JSON file with the following top-level fields:

FieldRequiredDescription
overlayYesThe version of the Overlay Specification being used, e.g. 1.1.0.
infoYesMetadata about the overlay: title, version, and an optional description (added in 1.1.0, CommonMark supported).
extendsNoA URI reference (absolute or relative) identifying the specific OpenAPI document the overlay is designed to update, e.g. ./tictactoe.yaml.
actionsYesAn ordered list of overlay actions to apply.

Each entry in actions supports:

FieldDescription
targetA JSONPath expression identifying which part(s) of the OpenAPI document to modify. As of version 1.1.0, this must be fully RFC 9535-compliant JSONPath.
updateAn object, array, or primitive value to deep-merge into the matched node(s).
removeA boolean (true) that deletes the matched node(s).
copyA JSONPath expression selecting a node in the same document to copy into the matched node(s) — added in version 1.1.0.
descriptionAn optional human-readable note explaining what the action does.

Only one of update, remove, or copy should be set per action — if both update and copy are present, update is ignored.

Step 1: Declare the Overlay and What It Targets #

Start with the overlay version and info block, optionally pointing at the base document with extends:

overlay: 1.1.0
info:
  title: Public API Overlay
  version: 1.0.0
  description: Strips internal-only endpoints and rewrites the public description.
extends: ./api.yaml
actions: []

Step 2: Target Nodes With JSONPath #

Every action needs a target expression to select the node(s) it applies to. Some common patterns:

$.info                                    # the info object
$.paths.*                                 # every path item
$.paths.*.*.responses                     # every response object, across all operations
$.components.schemas.User                 # the User schema component
$.paths['/orders'].post.summary           # the summary of the POST /orders operation
$.paths.*.get.tags[?@ == 'dummy']         # a specific tag value inside an array

Because target expressions must be RFC 9535-compliant, some filter expressions may need extra parentheses depending on your tooling’s JSONPath implementation, e.g. parameters[?(@.name=='filter')] instead of parameters[?@.name=='filter'].

Step 3: Choose an Action #

update — Add or Replace Values #

update performs a deep merge into the matched node, similar to JSON Merge Patch (RFC 7396). Keys not mentioned are preserved.

overlay: 1.1.0
info:
  title: Update info and one operation
  version: 1.0.0
actions:
  - target: $.info
    update:
      description: "This is the public-facing version of our API."
  - target: $.paths['/users/{id}'].get
    update:
      summary: "Retrieve a user by their unique identifier"
      x-internal-note: "Cached for 60 seconds"

Since version 1.1.0, update also works directly against primitive-valued nodes:

- target: $.paths['/foo'].get.description
  update: This is the new description

remove — Delete Nodes #

remove deletes the matched node entirely. It is commonly used to strip internal or administrative endpoints before publishing public documentation:

overlay: 1.1.0
info:
  title: Remove an internal endpoint
  version: 1.0.0
actions:
  - target: $.paths['/internal/admin']
    remove: true

Since version 1.1.0, remove also works against a single primitive entry inside an array, such as one tag among several:

- target: $.paths.*.get.tags[?@ == 'dummy']
  remove: true

copy — Duplicate or Move Nodes #

copy, introduced in version 1.1.0, merges in a value selected from elsewhere in the same document instead of a literal value written in the overlay. This is what makes renaming or moving a node possible with overlays alone:

overlay: 1.1.0
info:
  title: Rename the items path
  version: 1.0.0
actions:
  - target: '$.paths'
    update: { "/new-items": {} }
  - target: '$.paths["/new-items"]'
    copy: '$.paths["/items"]'
  - target: '$.paths["/items"]'
    remove: true
    description: 'moves (renames) the "items" path item to "new-items"'

This sequence follows the general recipe for any move or rename: ensure the destination exists, copy the source into it, then remove the source. Actions run in the order they appear, so the update action that creates /new-items must come before the copy action that fills it in.

Putting It All Together #

A single overlay file can combine update, remove, and copy freely, since actions are just applied in sequence against the base document:

overlay: 1.1.0
info:
  title: Public documentation overlay
  version: 1.2.0
  description: Prepares the internal API description for external publication.
extends: ./internal-api.yaml
actions:
  - target: $.info
    update:
      description: "This is the public-facing version of our API."
  - target: $.paths['/internal/metrics']
    remove: true
  - target: '$.paths'
    update: { "/orders-v2": {} }
  - target: '$.paths["/orders-v2"]'
    copy: '$.paths["/orders"]'
  - target: $.paths['/orders-v2'].post.summary
    update: "Create an order (v2 endpoint)"

Applying an Overlay #

Overlays are typically applied with a CLI tool as part of a build or CI/CD step, rather than by hand. Tools with documented support include:

Check the OAI Overlay Specification repository for the current list of tools and their supported Overlay Specification version, since copy, primitive update/remove, and the RFC 9535 requirement were only added in version 1.1.0.


Last updated on August 7, 2026.

This website is not affiliated with the OpenAPI Initiative.