Forward compatibility
Forward compatibility ensures older SDK versions continue to work correctly when APIs evolve by adding new fields, enum values, or other data. This guide covers how Speakeasy SDKs handle these changes automatically and how to configure additional resilience.
Quick reference
How SDKs handle API changes
Speakeasy SDKs automatically handle common API evolution scenarios without requiring code changes.
New fields
Adding new fields to API responses is always safe. SDKs ignore fields not defined in their model.
type: object
properties:
name:
type: string
created_at:
type: string
format: date-time
updated_at: # New field - ignored by older SDKs
type: string
format: date-timeNew enum values
APIs often add new enum values over time. The x-speakeasy-unknown-values extension enables SDKs to handle unknown values gracefully instead of throwing errors.
status:
type: string
x-speakeasy-unknown-values: allow
enum:
- active
- inactive
- pendingWhen the API adds a new value (e.g., suspended), each language handles it differently:
New response codes
Using status code ranges allows APIs to add specific codes without breaking SDKs:
responses:
"2xx":
description: Success response
content:
application/json:
schema:
$ref: "#/components/schemas/SuccessResponse"
"4xx":
description: Error response
content:
application/json:
schema:
$ref: "#/components/schemas/ErrorResponse"When an API returns an unexpected status code, SDKs match it to the appropriate range (2xx, 4xx, 5xx), parse the response using that range’s schema, and provide access to both the status code and response body.
Unexpected data
SDKs include additional mechanisms for handling unexpected data:
- Validation errors: Detailed error messages when unexpected data is received
- OneOf schemas: Attempts to match against known variants before failing
- Optional fields: Missing optional fields never cause validation errors
Configuring SDK resilience
Generator options enable additional forward compatibility features. These are configured in gen.yaml.
Forward-compatible enums
When forwardCompatibleEnumsByDefault is enabled (the default for new TypeScript SDKs), enums accept unknown values instead of rejecting the response:
const notification = await sdk.notifications.get(id);
// Before: Error: Expected 'email' | 'sms' | 'push'
// After: 'email' | 'sms' | 'push' | Unrecognized<string>Forward-compatible unions
When forwardCompatibleUnionsByDefault is enabled (TypeScript), discriminated unions accept unknown variants:
const account = await sdk.accounts.getLinkedAccount();
// Before: Error: Unable to deserialize into any union member
// After:
// | { type: "email"; email: string }
// | { type: "google"; googleId: string }
// | { type: "UNKNOWN"; raw: unknown }Lax mode (TypeScript)
When laxMode is set to lax (the default for new TypeScript SDKs), the SDK handles missing or mistyped fields by applying zero-value defaults and type coercions:
- Missing required strings become
"" - Missing required numbers become
0 - Missing required booleans become
false - Missing required dates become
Date(0)(Unix epoch) - Missing required bigints become
0n - Missing required literals become the literal value
- String
"true"and"false"are coerced to booleans - Numeric strings are coerced to numbers
- Numbers are coerced to dates (treated as milliseconds)
- Strings are coerced to bigints
- Any non-string value is coerced to string via
JSON.stringify()
Lax mode only affects response deserialization and never lies about types.
Go zero-value defaults
Go SDKs can achieve similar resilience with respectRequiredFields: false, which applies zero-value defaults for missing required fields. However, Go does not perform type coercions like TypeScript’s lax mode.
Smart union deserialization
When unionStrategy is set to populated-fields (the default for new TypeScript and Go SDKs), the SDK picks the best union variant by trying all types and returning the one with the most matching fields. When there’s a tie, it picks the variant with the fewest coerced or inexact fields.
This prevents issues where one union variant is a subset of another and the wrong variant gets selected due to ordering.
Per-schema overrides
Individual enums and unions can override global defaults using x-speakeasy-unknown-values: allow or x-speakeasy-unknown-values: disallow in the OpenAPI spec. See the TypeScript configuration reference for all available options.
Evolving APIs safely
Best practices for making changes without breaking existing SDK users.
Deprecating fields
Mark fields as deprecated before removing them:
properties:
name:
type: string
sku:
type: string
deprecated: true
x-speakeasy-deprecation-message: We no longer support the SKU property.This keeps fields accessible to older SDKs while new SDKs show deprecation warnings. When removing a field entirely:
- Mark the field as optional first
- Add deprecation notices
- Allow time for users to update
- Remove the field after a suitable deprecation period
Forward-compatible union patterns
To create unions that handle future data types, use the oneOf pattern with a string fallback:
oneOf:
- { type: "dog" }
- { type: "cat" }
- { type: string }This provides strongly typed handling for known variants while gracefully capturing future variants as strings.
Versioning strategies
Common approaches to manage breaking changes:
- Path-based versioning:
/v1/resource,/v2/resource - Header-based versioning:
Api-Version: 2023-01-01 - Multiple versions: Maintain multiple API versions during migration periods
Adding defaults
When making required fields optional, include default values:
properties:
status:
type: string
default: "active"Detecting breaking changes
The OpenAPI diff tool identifies potential breaking changes:
speakeasy openapi diff --base v1.yaml --revision v2.yamlThis highlights changes like removing required fields, changing field types, or modifying oneOf schemas.
Automatic SDK versioning
Speakeasy manages SDK versions based on the nature of changes:
- Patch: Non-breaking changes
- Minor: Backward-compatible additions
- Major: Breaking changes
When generating SDKs, Speakeasy detects breaking changes and provides clear notifications about what changed and how to handle the transition.
Related resources
For more information about handling breaking changes, see the breaking changes guide.
Last updated on