Skip to content
FeedbackDashboard

Transforms Reference

Complete technical reference for OpenAPI spec transforms

For practical examples and common use cases, see the transforms guide.

Transforms modify your OpenAPI spec during SDK generation. Define them in stainless.yaml under openapi.transformations. Stainless applies transforms in order using JSONPath Plus queries.

openapi:
transformations:
- command: update # Command name
reason: "Why this transform exists"
args:
target: "$.path.to.field"
value: "new value"

Transforms fail loudly when paths don’t exist or operations conflict. All values are deep-cloned to prevent shared references.

Replace values at existing paths. Fails if path doesn’t exist.

Arguments:

  • target (string | Array): JSONPath query to value(s) to replace
  • value (any): New value to set
  • template (boolean, optional): Enable {{value}} substitution for strings

Examples:

# Replace simple value
- command: update
args:
target: "$.info.version"
value: "2.0.0"
# Fix types across endpoints
- command: update
args:
target: '$.paths..parameters[?(@.name == "account_id")].schema.type'
value: "string"
# String templating: append
- command: update
args:
target: "$.paths./v1/users.get.summary"
value: "{{value}}\n\nDEPRECATED: Use /v2/users"
template: true
# Schema matching: replace duplicates
- command: update
args:
target:
- matches_schema: $.components.schemas.ErrorTemplate
ignore: $.components.schemas.ErrorTemplate
value:
$ref: "#/components/schemas/Error"

String templating: When template: true, value must contain {{value}}. Each target must be a string. The placeholder gets replaced with the current value.

Examples:

# Append text
- command: update
args:
target: "$.paths./v1/users.get.description"
value: "{{value}}\n\n⚠️ Deprecated. Use /v2/users."
template: true
# Prepend text
- command: update
args:
target: '$.paths./beta/*.get.summary'
value: "[BETA] {{value}}"
template: true
# Wrap text
- command: update
args:
target: "$.components.schemas.User.properties.id.description"
value: "**{{value}}**"
template: true

When targeting multiple paths, {{value}} is replaced with each target’s individual current value.

Schema matching: Use matches_schema to find schemas that exactly match a template (deep equality). The ignore field excludes paths from replacement.

Add items to arrays or properties to objects. Fails if object property already exists (safety feature).

Arguments:

  • target (string | Array): JSONPath query to array(s) or object(s)
  • value (any): Item(s) to push (arrays) or properties to add (objects)

Examples:

# Add to array
- command: append
args:
target: "$.components.schemas.User.required"
value: "id"
# Add properties (fails if exists)
- command: append
args:
target: "$.components.schemas.User.properties"
value:
id:
type: "string"
format: "uuid"
# Add to multiple arrays
- command: append
args:
target: "$.components.schemas.*.required"
value: "id"

For objects, append fails if any property already exists. This alerts you when the spec is fixed and your transform becomes redundant. Use merge if you want to overwrite.

Deep-merge object into targets. Overwrites existing properties.

Arguments:

  • target (string | Array): JSONPath query to object(s)
  • value (object): Object to merge

Examples:

# Add x-stainless extension
- command: merge
args:
target: '$.paths..parameters[?(@.name == "limit")]'
value:
schema:
x-stainless-skip: ["terraform"]
# Language-specific naming
- command: merge
args:
target: "$.components.schemas.Request.properties.timeout"
value:
x-stainless-naming:
python:
method_argument: "api_timeout"
# Merge into multiple schemas
- command: merge
args:
target: "$.components.schemas.*"
value:
additionalProperties: false

Nested objects merge recursively. Use merge for permanent overrides, append for temporary fixes.

Delete nodes or specific keys from objects.

Arguments:

  • target (string | Array): JSONPath query to node(s) to remove
  • keys (Array<string>, optional): If target is object, remove only these keys. Otherwise removes entire node.

Examples:

# Remove entire nodes
- command: remove
args:
target:
- "$.paths.*.*.examples"
- "$.components.schemas.*.example"
# Remove specific keys
- command: remove
args:
target: "$.components.schemas.User.properties.middleName"
keys: ["default"]
# Remove with filter
- command: remove
args:
target: '$.paths..parameters[?(@.deprecated == true)]'

When removing from arrays, handles index shifting correctly by removing in descending order.

Copy value from source to one or more destinations. Creates destination if parent exists.

Arguments:

  • from (string): JSONPath query to source (must match exactly one node)
  • to (string | Array): JSONPath query to destination(s). Creates if doesn’t exist (parent must exist).

Examples:

# Copy schema
- command: copy
args:
from: "$.components.schemas.User"
to: "$.components.schemas.Admin"
# Copy to multiple destinations
- command: copy
args:
from: "$.components.schemas.NotFoundError"
to:
- "$.paths./users/{id}.get.responses.404.content.application/json.schema"
- "$.paths./posts/{id}.get.responses.404.content.application/json.schema"
# Extract inline schema
- command: copy
args:
from: "$.paths./users.post.responses.400.content.application/json.schema"
to: "$.components.schemas.BadRequestError"

Values are deep-cloned to each destination. Cannot create array indices (use append instead).

Move or rename a value. Efficiently renames within same parent, otherwise copies and removes.

Arguments:

  • from (string): JSONPath query to source (must match exactly one node)
  • to (string): JSONPath query to destination

Examples:

# Rename schema
- command: move
args:
from: "$.components.schemas.user_response"
to: "$.components.schemas.UserResponse"
# Rename property
- command: move
args:
from: "$.components.schemas.User.properties.firstName"
to: "$.components.schemas.User.properties.first_name"
# Move across parents
- command: move
args:
from: "$.components.schemas.User"
to: "$.components.parameters.UserParam"

If source and destination share the same parent, move renames the key without copying. Otherwise, it copies to the destination and removes from the source.

All transforms use JSONPath Plus for targeting.

Common patterns:

# Exact path
target: "$.components.schemas.User.properties.id"
# Bracket notation for special characters
target: '$.paths["/users/{id}"].get'
# Wildcard (immediate children)
target: "$.components.schemas.*"
# Recursive descent
target: "$..parameters"
target: "$.paths..responses"
# Array index
target: "$.servers[0]"
target: "$.paths./users.get.parameters[2]"
# Filter by value
target: '$.paths..parameters[?(@.in == "query")]'
target: '$.components.schemas[?(@.type == "object")]'
# Filter by property
target: '$.paths..parameters[?(@.name == "account_id")]'
# Multiple conditions
target: '$.paths..parameters[?(@.in == "query" && @.required == true)]'
# Combining wildcards and filters
target: '$.paths.*.get.parameters[?(@.name == "limit")]'

Multiple targets:

target:
- "$.components.schemas.User.example"
- "$.components.schemas.Post.example"

Always quote paths with special characters or filter expressions. Use single quotes for paths containing double quotes.

Find all schemas that exactly match a template:

target:
- matches_schema: <path-to-template>
ignore: <optional-path-to-exclude>

Example:

- command: update
args:
target:
- matches_schema: $.components.schemas.ErrorTemplate
ignore: $.components.schemas.ErrorTemplate
value:
$ref: "#/components/schemas/Error"

Traverses entire spec, compares each schema with template for exact match (deep equality), returns matches. Use ignore to exclude the template itself.

Can mix with explicit paths:

target:
- "$.components.schemas.SpecificError"
- matches_schema: $.components.schemas.ErrorPattern

Path not found: “JSONPath did not match any nodes” Query didn’t find anything. Check for typos or verify the path exists.

Constraint violation: “Properties already exist… use ‘merge’ instead” Using append on existing property (safety feature). Remove transform if the spec was fixed, or switch to merge to overwrite.

Type mismatch: “Target must point to objects. Got string” Command expects specific type but found something else. Verify target path points to expected structure.

Invalid operation: “Cannot create array index” Operation doesn’t support this structure. Use appropriate command (e.g., append for arrays).

Root targeting: “Cannot update document root” Targeting $ not allowed. Target specific fields within the document.