Skip to content
FeedbackDashboard

SDK and config editions

Editions allow us to safely make updates and improvements to SDKs and the Stainless config that aren’t backwards-compatible, like changing default behavior or renaming a property. Every time we make a breaking change, we release a new version in the form of an “edition” which you can explicitly opt-in to when you’re ready.

There are two types of editions:

  • Top-level editions are for general and cross-language changes and have a date-based identifier (e.g., 2025-10-08)
  • Language-specific editions only impact a specific programming language and have an identifier that includes the language and date (e.g., typescript.2025-10-10) Each edition includes all of the improvements made up to and including the date in its identifier.

The editions we use for your projects are defined in your Stainless config. The top-level edition is specified in the top-level edition property, and language-specific editions are specified inside specific language targets:

# Top-level edition
edition: 2025-10-08
# ...
targets:
typescript:
# Language-specific edition
edition: typescript.2025-10-10
# ...

When no edition property is present, the oldest available edition will be used. This applies to both the top-level edition property and the edition properties inside language targets. Also note that the top-level edition doesn’t cascade down into language targets. If you have a top-level edition set but a language target doesn’t have an edition property, for example, that language will use the oldest edition, not the one set at the top-level.

The top-level and language-specific editions in your config don’t need to match, and language-specific editions also don’t have to match each other. This gives you the flexibility to incrementally adopt new editions one language at a time without introducing breaking changes across multiple targets at once. Note that we may release language-specific editions without a corresponding top-level edition, making it impossible to have the same top-level and language-specific versions.

Below are all available editions and what was changed.

When choosing a name for a union variant, prefer the corresponding schema’s title property over its name in #/components/schemas.

We try the following options for union variant names, in order:

  1. If the variant is defined as a model, use the model name.
  2. Use the variant’s x-stainless-variantName property if it exists.
  3. Use the variant’s title property if it exists.
  4. If the variant is defined as a top-level schema in #/components/schemas, use the name of the schema.
  5. Use a generic name like UnionVariant0.

For example, suppose your OpenAPI spec includes the following schemas:

components:
schemas:
Address:
oneOf:
- $ref: '#/components/schemas/Coordinates' # for drone delivery
- $ref: '#/components/schemas/POBox'
- $ref: '#/components/schemas/StreetAddress'
Coordinates:
type: object
x-stainless-variantName: DroneDeliveryCoordinates
properties:
# ... properties omitted
POBox:
type: object
title: CustomerPOBox
properties:
# ... properties omitted
StreetAddress:
type: object
properties:
# ... properties omitted

Let’s assume that none of these schemas is defined as a model.

  • We’ll derive the variant name for Coordinates from its x-stainless-variantName property, DroneDeliveryCoordinates.
  • POBox doesn’t specify x-stainless-variantName, so we’ll derive its variant name from its title property, CustomerPOBox.
  • StreetAddress doesn’t specify x-stainless-variantName or title, so we’ll fall back to its name in #/components/schemas, StreetAddress.

For instance, in TypeScript we’ll generate the following code:

export type Address =
| Address.DroneDeliveryCoordinates
| Address.CustomerPoBox
| Address.StreetAddress;

Before this edition, we tried the name in #/components/schemas before the title property, so we generated the following code for this schema:

export type Address =
| Address.DroneDeliveryCoordinates
| Address.PoBox // instead of Address.CustomerPoBox
| Address.StreetAddress;

Note that updating to this edition does not affect variants that are configured as models or specify x-stainless-variantName, since the model name and x-stainless-variantName take precedence over the title and #/components/schemas name for union variant naming in all editions.

To revert to the previous behavior for union variant naming, set prefer_title_over_refnames to false at the top level in your Stainless config:

prefer_title_over_refnames: false

Enables per-endpoint security by default. For example, if your OpenAPI spec looks like this:

security:
- BearerAuth: []
- ApiKeyAuth: []
securitySchemes:
BearerAuth:
type: http
scheme: bearer
ApiKeyAuth:
type: apiKey
name: api-key
in: header
paths:
/cards:
post:
security:
- BearerAuth: []
# ... responses omitted

And your stainless config:

settings:
client_opts:
bearer_token:
type: string
nullable: true
auth:
security_scheme: BearerAuth
api_key:
type: string
nullable: true
auth:
security_scheme: ApiKeyAuth
resources:
cards:
methods:
create: post /cards

When instantiating the SDK with both options:

from acme import Acme
client = Acme(
api_key="my-api-key",
bearer_token="my-bearer-token",
)
client.cards.create()

Previously, the SDK sent both the api-key and Authorization headers, which could cause authentication errors depending on how your API handles multiple authentication schemes.

Now the SDK will only send the Authorization header, as that is the only scheme configured for that endpoint in security.

To revert to the previous behavior of sending all configured options, set per_endpoint_security to false:

settings:
per_endpoint_security: false

Placeholder edition with no functional changes. This will be the default edition for new projects.

The first top-level edition for our original base functionality. This will be the default edition used if the top-level edition property is not present.