Browse pages
API Compatibility
API compatibility keeps consumers that release on their own schedule working when the API or its published events change, including public, partner, and mobile clients. This page states how a project classifies each contract and event change, versions breaking ones, keeps supported versions alive, and retires them with notice. A team with such consumers applies it, so its consumers keep working across releases instead of breaking on deploy day.
Stack: any Layer: web-api
Activation#
Activation scope: project.
Applicable specification kinds: None.
The consumer enables compat for public APIs, partner clients, mobile clients, independently deployed consumers, or consumers of its published events. APIs whose consumers always release together with them stay under litespec/backend/api#treat-openapi-as-a-generated-contract. A project whose first deployment holds no customer data yet defers these rules through the stage extension.
Baseline Relationship#
This extension replaces no baseline provision.
Each domain event stays inside the product; each fact consumed outside it is an integration event, as the behavior page states.
This extension switches on no optional record type.
Standards#
Classify Independent-Consumer Changes#
ruleruleguidancelitespec/ext/compat#classify-independent-consumer-changesAn API change reviewer MUST classify each contract change that affects an independently deployed consumer.
Applies toartifact: any
Why
Every contract change reaches consumers the project does not deploy. Classifying each one decides whether consumers need a new version, a review, or nothing at all. An unclassified change ships the decision to consumers as a surprise.
Checka reviewer answers
Reviewed forWhich independent-consumer contract changes lack a classification? Look at the change reviews.
Marked guidance: a reviewer answers this question.
Classify Breaking Contract Changes#
ruleruleguidancelitespec/ext/compat#classify-breaking-contract-changesAn API change reviewer MUST classify removal, rename, required input, narrowed value, response, status, or authentication changes as breaking.
Applies toartifact: any
Why
A consumer can depend on any element of the contract: a field it reads, a status it branches on, an authentication scheme it implements. Removing, renaming, narrowing, or retyping any of them breaks the consumer that depended on it. Calling each such change breaking routes it to versioning instead of silent release.
Checka reviewer answers
Reviewed forWhich removed, renamed, narrowed, retyped, or authentication changes lack a breaking verdict? Look at the change reviews.
Marked guidance: a reviewer answers this question.
Treat Removed Behavior Fields as Breaking#
ruleruleguidancelitespec/ext/compat#treat-removed-behavior-fields-as-breakingAn API change reviewer MUST classify removal of a query output field, a refusal code, or an integration-event payload field as breaking.
Applies toartifact: any
Why
Consumers read query output fields, branch on refusal codes, and parse integration-event payloads, so a removed field breaks every consumer that relied on it while the route stays green. Calling each such removal breaking routes it to versioning and notice instead of silent release.
Checka reviewer answers
Reviewed forWhich removed output fields, refusal codes, or integration-event payload fields lack a breaking verdict? Look at the change reviews.
Marked guidance: a reviewer answers this question.
Classify Compatible Additions#
ruleruleguidancelitespec/ext/compat#classify-compatible-additionsAn API change reviewer MUST classify an optional field, endpoint, or query parameter as compatible when existing clients retain behavior.
Applies toartifact: any
Why
An optional field, endpoint, or query parameter asks nothing of existing callers: they send and interpret the same values as before. Classifying these as compatible keeps routine growth cheap. Treating them as breaking would version the API for changes nobody has to adopt.
Checka reviewer answers
Reviewed forWhich optional additions lack a record of why existing behavior stays? Look at the change reviews.
Marked guidance: a reviewer answers this question.
Review Exhaustive Consumer Changes#
ruleruleguidancelitespec/ext/compat#review-exhaustive-consumer-changesAn API change reviewer MUST require consumer review for an added enum value or polymorphic subtype.
Applies toartifact: any
Why
Generated clients often switch exhaustively over enum values and discriminator cases. A new value that the server now sends reaches a client with no branch for it, which rejects a valid response. Consumer review checks that each client handles the new case before it ships.
Checka reviewer answers
Reviewed forWhich added enum values or discriminator cases shipped without consumer review? Look at the consumer reviews.
Marked guidance: a reviewer answers this question.
Preserve Stable Error Codes#
ruleruleguidancelitespec/ext/compat#preserve-stable-error-codesAn API change reviewer MUST classify removal or reassignment of a stable Problem Details code as breaking.
Applies toartifact: any
Why
Consumers branch on stable Problem Details codes the way they branch on statuses. Removing or reassigning a code breaks that branch while the status stays green. Treating the code as breaking keeps error handling stable across versions.
Checka reviewer answers
Reviewed forWhich removed or reassigned stable codes lack a breaking verdict? Look at the change reviews.
Marked guidance: a reviewer answers this question.
Resolve Uncertain Classifications Safely#
ruleruleguidancelitespec/ext/compat#resolve-uncertain-classifications-safelyAn API change reviewer MUST classify an unclear contract change as breaking and require consumer review.
Applies toartifact: any
Why
A structural diff cannot prove every change compatible: some changes need a person to judge their effect on consumers. Classifying the unclear ones as breaking routes them to consumer review instead of release. The cost of a needless review is smaller than the cost of a broken consumer.
Checka reviewer answers
Reviewed forWhich unclear changes shipped as compatible without consumer review? Look at the change reviews.
Marked guidance: a reviewer answers this question.
Record Breaking Behavior Changes as Decisions#
ruleruleguidancelitespec/ext/compat#record-breaking-behavior-changes-as-decisionsAfter production, a breaking Behavior change MUST travel as a decision naming its consumer impact.
Applies toartifact: record:decision
Why
A breaking change past production breaks promises consumers release against, so the decision states the impact: which consumers break, what they must change, and when the old shape leaves. A developer review alone cannot accept breaking what the product promised.
Checka reviewer answers
Reviewed forWhich breaking Behavior changes past production lack a decision naming their consumer impact? Look at the decisions.
Marked guidance: a reviewer answers this question.
Retain Release Baselines#
ruleruleguidancelitespec/ext/compat#retain-release-baselinesAn API owner MUST store each release OpenAPI document as a retained baseline artifact.
Applies toartifact: any
Why
Each release stores its OpenAPI document as an immutable baseline. Later changes diff against it instead of against memory or a mutable file. Without a retained baseline, the project cannot prove what changed between two releases.
Checka reviewer answers
Reviewed forWhich releases lack a retained OpenAPI baseline? Look at the release artifacts.
Marked guidance: a reviewer answers this question.
Diff Release Contracts#
ruleruleguidancelitespec/ext/compat#diff-release-contractsThe project MUST compare the current OpenAPI document with the selected supported baseline, both locally and in continuous integration.
Applies toartifact: any
Why
The diff against the supported baseline runs both locally and in continuous integration. The local run catches a breaking change while it is cheap to rework. The CI run catches it when the local run was skipped.
Checka reviewer answers
Reviewed forWhich changes skipped the local or continuous integration diff against the baseline? Look at the local runs and the CI runs.
Marked guidance: a reviewer answers this question.
Reject Breaking Diffs Without Authorization#
ruleruleguidancelitespec/ext/compat#reject-breaking-diffs-without-authorizationContinuous integration MUST fail a breaking diff unless a new API version or a recorded consumer decision authorizes it.
Applies toartifact: any
Why
A breaking diff that fails CI stops until a new API version or a recorded consumer decision authorizes it. The failure forces the compatibility decision before release, while versioning is still possible. A warning nobody has to answer authorizes nothing.
Checka reviewer answers
Reviewed forWhich breaking diffs passed without a new version or a recorded decision? Look at the CI runs.
Marked guidance: a reviewer answers this question.
Assign Operation IDs#
ruleruleguidancelitespec/ext/compat#assign-operation-idsEvery operation exposed to an independent consumer MUST have a deliberate operationId, except an endpoint whose shape a specification outside the project fixes.
Applies toartifact: endpoint
Why
Generated clients turn each operationId into a method name, and tools use it to reference the operation. A deliberate identifier keeps those names stable and meaningful. An endpoint whose shape an outside specification fixes is exempt, because the project does not own that contract.
Example
An OAuth redirect endpoint, an OIDC discovery document, a provider webhook receiver, and a well-known resource each carry a shape the other party defines.
Checka reviewer answers
Reviewed forWhich independent-consumer operations lack a deliberate operationId? Look at the OpenAPI document.
Marked guidance: a reviewer answers this question.
Retain Compatible Operation IDs#
ruleruleguidancelitespec/ext/compat#retain-compatible-operation-idsA compatible API change MUST retain the existing operationId.
Applies toartifact: endpoint
Why
A compatible change promises existing consumers keep working. Renaming the operationId breaks that promise for every generated client and every stored operation reference. The identifier stays until a new version takes over.
Checka reviewer answers
Reviewed forWhich compatible changes renamed the operationId? Look at the OpenAPI diff.
Marked guidance: a reviewer answers this question.
Assign Versioned Operation IDs#
ruleruleguidancelitespec/ext/compat#assign-versioned-operation-idsA new API version MUST assign a new operation ID when its operation contract changes.
Applies toartifact: endpoint
Why
The new version needs its own contract names so the retained version keeps its own. A new operationId for each changed operation separates the two. Sharing one identifier across versions would let the new contract rename the old one.
Checka reviewer answers
Reviewed forWhich new versions reuse the operation ID of a changed contract? Look at the versioned OpenAPI documents.
Marked guidance: a reviewer answers this question.
Version Breaking Contracts#
ruleruleguidancelitespec/ext/compat#version-breaking-contractsAn API owner MUST use a new route or documented media-type version for a breaking contract.
Applies toartifact: endpoint
Why
Breaking changes need a boundary: a new route or a documented media-type version. Both contracts then serve at once, and each consumer moves on its own schedule. Without the boundary, one contract serves two incompatible expectations.
Checka reviewer answers
Reviewed forWhich breaking contracts ship without a new route or media-type version? Look at the versioned API surface.
Marked guidance: a reviewer answers this question.
Retain Supported Versions#
ruleruleguidancelitespec/ext/compat#retain-supported-versionsAn API owner MUST keep the previous version available for its declared support window.
Applies toartifact: any
Why
A consumer the project does not deploy moves on its own release cadence. The declared support window states how long the previous version stays available for that move. Removing it early strands consumers that kept to the published plan.
Checka reviewer answers
Reviewed forWhich previous versions left before their support window? Look at the deployed versions beside the declared window.
Marked guidance: a reviewer answers this question.
Record Version Retirement#
ruleruleguidancelitespec/ext/compat#record-version-retirementA versioning decision MUST name each affected consumer, the deadline, and the removal condition, with the decision recorded before any removal.
Applies toartifact: record:decision
Why
A removal touches consumers the project does not control, so the decision names each affected consumer, the deadline, and the removal condition. Recording happens before any removal, while the plan can still change. An unrecorded retirement removes first and notifies whoever complains.
Checka reviewer answers
Reviewed forWhich retirements lack affected consumers, a deadline, a removal condition, or recording before removal? Look at the versioning decisions.
Marked guidance: a reviewer answers this question.
Signal Planned Public Removal#
ruleruleguidancelitespec/ext/compat#signal-planned-public-removalA public operation scheduled for removal MUST expose a documented deprecation signal.
Applies toartifact: endpoint
Why
Consumers discover a planned removal only when the API tells them. A documented deprecation signal, such as Deprecation and Sunset headers, announces the removal on the operation itself. A removal with no signal arrives as an outage to every consumer that missed the release notes.
Checka reviewer answers
Reviewed forWhich operations scheduled for removal lack a deprecation signal? Look at the public operations.
Marked guidance: a reviewer answers this question.
Publish Deprecation Context#
ruleruleguidancelitespec/ext/compat#publish-deprecation-contextA public operation scheduled for removal MUST appear in the consumer CHANGELOG.md.
Applies toartifact: any
Why
Headers announce the removal on the operation, but consumers plan from release notes. The consumer CHANGELOG.md names each operation scheduled for removal in the one place consumers already read. A deprecation missing from the changelog reaches only the consumers that inspect headers.
Checka reviewer answers
Reviewed forWhich operations scheduled for removal are missing from the consumer changelog? Look at the consumer CHANGELOG.md.
Marked guidance: a reviewer answers this question.
Record Deprecation Conditions#
ruleruleguidancelitespec/ext/compat#record-deprecation-conditionsA deprecation decision MUST record the sunset date and replacement operation, with nothing removed before the decision is recorded.
Applies toartifact: record:decision
Why
A deprecation decision records the sunset date and the replacement operation, so each consumer knows when to move and where to go. Nothing is removed before the decision is recorded. A removal without a recorded replacement strands the consumer that depended on the old operation.
Checka reviewer answers
Reviewed forWhich deprecations lack a sunset date, a replacement, or recording before removal? Look at the deprecation decisions.
Marked guidance: a reviewer answers this question.
Treat Errors as Contracts#
ruleruleguidancelitespec/ext/compat#treat-errors-as-contractsAn API owner MUST treat Problem Details type, code, field-error codes, and documented statuses as versioned contract elements.
Applies toartifact: any
Why
Error handling is consumer code: it branches on Problem Details type, code, field-error codes, and documented statuses. Versioning those elements with the contract keeps error handling working across releases. An error shape that changes outside versioning breaks the consumer's failure path, which is the path least tested.
Checka reviewer answers
Reviewed forWhich type, code, field-code, or status changes shipped outside versioning? Look at the versioned error surface.
Marked guidance: a reviewer answers this question.
Gate New Error Outcomes#
ruleruleguidancelitespec/ext/compat#gate-new-error-outcomesAn API owner MUST add an error outcome only when existing consumers safely handle an unknown code.
Applies toartifact: any
Why
A new error outcome reaches consumers written before it existed. Adding it only when existing consumers handle an unknown code safely keeps old clients working against the new contract. An outcome old clients cannot parse turns their error path into a crash.
Checka reviewer answers
Reviewed forWhich added error outcomes break existing consumers on unknown codes? Look at the consumer error handling.
Marked guidance: a reviewer answers this question.
Exercise Generated Consumers#
ruleruleguidancelitespec/ext/compat#exercise-generated-consumersAn API owner MUST test each first-party generated client against the changed OpenAPI document, with each client compiling and exercising its changed operations.
Applies toartifact: test
Why
A structural diff compares documents; it never compiles a client. Testing each first-party generated client against the changed document compiles it and exercises its changed operations. The client's compiler and its exhaustive switches catch the breaks the diff cannot see.
Checka reviewer answers
Reviewed forWhich first-party clients skip compiling or exercising the changed contract? Look at the client test runs.
Marked guidance: a reviewer answers this question.
Declare Published Facts as Integration Events#
ruleruleguidancelitespec/ext/compat#declare-published-facts-as-integration-eventsA fact consumed outside the product MUST be declared as an integration event with its direction, payload, and trust.
Applies toartifact: record:integration-event
Why
A consumer outside the product reads the fact without reading the product's code, so the integration-event record states what the consumer may rely on: the direction, the payload with its classifications, and the trust readers place in it. litespec/core/edges#describe-every-integration-event-for-its-direction states the record. An undeclared fact reaches outside consumers as an implementation detail that changes without notice.
Checka reviewer answers
Reviewed forWhich outside-consumed facts lack an integration-event record with direction, payload, and trust? Look at the integration-event records beside the outside consumers.
Marked guidance: a reviewer answers this question.
Classify Integration Event Changes#
ruleruleguidancelitespec/ext/compat#classify-integration-event-changesAn API change reviewer MUST classify each integration-event change as breaking, compatible, or needing consumer review under litespec/ext/compat#classify-breaking-contract-changes, litespec/ext/compat#classify-compatible-additions, and litespec/ext/compat#review-exhaustive-consumer-changes.
Applies toartifact: any
Why
An integration event is a contract with consumers the project does not deploy, so its changes need the same verdicts as HTTP contract changes. Reusing the contract classification keeps one meaning of breaking, compatible, and needs-review across both surfaces. A separate event verdict would let one change read as compatible for events and breaking for HTTP.
Checka reviewer answers
Reviewed forWhich integration-event changes lack a breaking, compatible, or needs-review verdict? Look at the event reviews.
Marked guidance: a reviewer answers this question.
Version Breaking Integration Events#
ruleruleguidancelitespec/ext/compat#version-breaking-integration-eventsAn API owner MUST carry a breaking integration-event change in a new event version beside the retained version.
Applies toartifact: record:integration-event
Why
Outside consumers move on their own release cadence, so the breaking change ships beside the retained version instead of replacing it. Each consumer moves to the new version on its own schedule. Without the retained version, one event serves two incompatible expectations.
Checka reviewer answers
Reviewed forWhich breaking event changes ship without a new version beside the retained one? Look at the integration event versions.
Marked guidance: a reviewer answers this question.
Retire Integration Events with Notice#
ruleruleguidancelitespec/ext/compat#retire-integration-events-with-noticeAn API owner MUST retire an integration event version only after its declared support window with a deprecation notice to its consumers.
Applies toartifact: any
Why
A retired version strands every consumer still reading it, so the declared support window states how long the version stays available and the notice tells consumers when to move. Retiring early or silently turns a planned removal into an outage for the consumers that kept to the published plan.
Checka reviewer answers
Reviewed forWhich retired event versions left before their support window or without notice? Look at the retirement records beside the event consumers.
Marked guidance: a reviewer answers this question.
Conventions#
Store Current OpenAPI Source#
conventiondefaultguidancelitespec/ext/compat#store-current-openapi-sourceStore the current source artifact at apps/api/openapi/{ProjectName}.json.
ReplacementA consumer records a contract-source convention naming where its current OpenAPI artifact lives.
Applies toartifact: any
Why
Source generation and contract review both need the current OpenAPI artifact. One predictable path keeps generation, review, and the diff reading the same file. A second copy drifts from the first.
Checka reviewer answers
Reviewed forWhich current OpenAPI artifacts live outside the documented path or the recorded local convention? Look at apps/api/openapi/.
Marked guidance: a reviewer answers this question.
Keep Baseline References Immutable#
conventiondefaultguidancelitespec/ext/compat#keep-baseline-references-immutableStore each supported baseline beside its contract owner or under an immutable retained-release reference.
ReplacementA consumer records a baseline convention naming where its immutable baselines live.
Applies toartifact: any
Why
A diff proves nothing when its comparison target can move. Baselines beside their contract owner or under an immutable release reference stay fixed. A mutable baseline lets a breaking change hide by moving the target.
Checka reviewer answers
Reviewed forWhich baselines move, or live outside the recorded local convention? Look at the baseline references.
Marked guidance: a reviewer answers this question.
Use One Diff Tool#
conventiondefaultguidancelitespec/ext/compat#use-one-diff-toolUse the same OpenAPI diff tool in local verification and continuous integration.
ReplacementA consumer records a diff-tool convention naming the OpenAPI diff tool its local run and continuous integration share.
Applies toartifact: any
Why
The local run and CI have to agree on what breaking means. One diff tool in both places gives one classification for each change. Two tools disagree on edge cases and teach developers to distrust the check.
Checka reviewer answers
Reviewed forWhich local runs or CI runs use a different diff tool than the recorded local convention? Look at the local runs and the CI runs.
Marked guidance: a reviewer answers this question.
Keep Problem Details Codes Stable#
conventiondefaultguidancelitespec/ext/compat#keep-problem-details-codes-stableKeep Problem Details error codes stable across compatible versions.
ReplacementA consumer records an error-code convention naming how its Problem Details codes evolve.
Applies toartifact: any
Why
Consumer error handling branches on these codes for years. Keeping them stable across compatible versions lets that handling survive routine releases. A renamed code forces every consumer to update its failure path for no behavior gain.
Checka reviewer answers
Reviewed forWhich Problem Details codes changed across compatible versions, or outside the recorded local convention? Look at the versioned error surface.
Marked guidance: a reviewer answers this question.
Dependencies#
Packages: None. A project that introduces an OpenAPI diff tool pins its version in the manifest.
Related extensions: stage for deferring these rules before first customer data.
Guides: None.