API StudioSDK StudioMonitoringMCP ServerSpec AuditFeatures
ComparePricingBlogDocs
Log inStart for free
API StudioSDK StudioMonitoringMCP ServerSpec AuditFeatures
ComparePricingBlogDocs
Log inStart for free
API StudioSDK StudioMonitoringMCP ServerSpec AuditFeatures
ComparePricingBlogDocs
Log inStart for free
Blog/Engineering
Engineering·September 11, 2026·5 min read

What counts as a breaking change when your SDK is generated

A one-line spec edit can break every call site your users wrote. Here is the table of what is additive, what is breaking, and which ones your spec diff will not warn you about.

#openapi#versioning#sdks#semver
What counts as a breaking change when your SDK is generated

When you hand-write an SDK, you know when you have broken it, because you had to edit the method that broke.

When you generate one, the break happens somewhere between a pull request that looked harmless and a regenerated package that no longer compiles for the people who installed it. Nobody wrote the breaking change. It fell out of the spec.

The uncomfortable part is that a spec diff is a bad predictor of an SDK diff. Some edits that look enormous are additive. Some that look like nothing are breaking in every typed language you publish.

The table

Spec change Effect on the generated client
Add an endpoint Additive
Add an optional parameter Additive, unless the argument style is positional
Add a required parameter Breaking. Every existing call site is now wrong
Rename a field Breaking in typed languages, silent in untyped ones
Change a response type Breaking in typed languages
Remove an endpoint Breaking. The method disappears
Change an operationId Breaking. The method is renamed

Four of those seven produce no interesting diff in the document. A renamed field is one word. A changed operationId is one word. Both compile fine on your side, because you are not the one who wrote the call site.

The two that catch people

Adding a required parameter. This reads as an addition, and additions are supposed to be safe. It is not an addition to the caller. Every existing invocation of that method is now missing an argument it must supply, and in a typed language that is a compile error across your users' codebases at once.

If you need a new input, make it optional and give it a default on the server. If the operation genuinely cannot work without it, you are shipping a new operation and it should have its own id.

Renaming a field. In TypeScript, Go, Java, Rust and Swift, a renamed response field is a compile error, which is the good outcome: the failure lands at build time with a clear message.

In Python, Ruby, PHP and Dart it is not. The generated model changes shape, the caller's attribute access keeps parsing, and the failure arrives at runtime in whatever code path first touches the old name. If you publish to both kinds of language from one spec, your untyped consumers are the ones who find out in production.

The version does not compute itself

This is the part people assume works differently than it does, so it is worth being direct.

The package version comes from info.version in your specification. It is propagated into the generated manifests on every build, so the version on npm and the version in your document agree by construction.

yaml
123
info:
  title: Acme API
  version: 2.4.0

Nothing infers a major bump from the diff. If you add a required parameter and leave info.version where it was, the package publishes with a version that says nothing happened. The table above is the input to a decision you make, not a decision the pipeline makes for you.

The corollary catches people too: editing the version inside a generated package.json or pyproject.toml does not survive. Those manifests are overwritten on every build. Change info.version in the spec.

Deprecate rather than remove

Removing an operation breaks callers at compile time, which sounds acceptable until you remember that the compile happens on their schedule and not yours. They upgrade for an unrelated reason, everything stops building, and now your removal is their incident.

Marking it deprecated instead surfaces the warning at compile time and keeps their code working. They get told, they get to plan, and you get to remove it in a release where removal is the headline rather than a surprise.

The generated client carries the deprecation through, so the notice appears where the method is used rather than in a changelog nobody read.

What to do before you publish

Read the diff as your users will experience it, not as your spec renders it. Three questions cover most releases.

Did any operation gain a required input, or lose an optional one it used to accept? That is a signature change in every language you publish.

Did any operationId change, including a change that looks like a typo fix? That is a method rename, and it is worth checking whether the tidy-up is worth the break. Overriding the generated method name for that endpoint keeps the public surface stable while the spec gets cleaned up.

Did any field in a response schema change name or type? Sort your published languages into typed and untyped, and decide which failure mode you are handing to which group.

Then set info.version to say what you concluded.

Where the SDK shape changes the answer

One row in that table has a qualifier, and it is worth pulling out: adding an optional parameter is additive only if the argument style is an object.

With an options object, a new optional field is invisible to existing calls. With positional arguments, adding a parameter shifts the position of everything after it, and a call site that compiled yesterday now passes the wrong value into the wrong slot. That is the worst class of break, because it can be type-correct and silently wrong.

This is why the generated clients promote a wide operation to a request object rather than growing an argument list, and why the argument style is worth a deliberate decision per language rather than an inherited default. The OpenAPI to Go SDK and OpenAPI to Java SDK pages show what each style produces at the call site.

Catch the ones that are already in your spec

Several rows in that table start as spec problems long before they become SDK problems. An operation with no declared response schema cannot tell you that its response type changed, because it never declared one. An operation with no operationId has a name that moves whenever its path does.

Our spec audit scores a document on exactly those grounds and names the operations responsible. It is free and it does not keep your spec. Run it before the release where one of these bites, rather than after.

← PreviousAPI-first in practice: what changes when the spec is the source of truth

Related articles

Your operationIds are your public method names, and unique is not enough
Engineering·5 min read

Your operationIds are your public method names, and unique is not enough

An operationId is not documentation metadata. It is the name your users type. Here is why uniqueness does not save you, and what actually collides.

September 9, 2026
Should you hand-write your SDKs or generate them?
Engineering·5 min read

Should you hand-write your SDKs or generate them?

The honest answer depends on how many languages you ship and how often your API changes. For one language and a stable API, hand-writing wins.

September 9, 2026
41% of APIs drift within 30 days, and most of it is invisible
Engineering·5 min read

41% of APIs drift within 30 days, and most of it is invisible

Schema drift is not usually a breaking change. It is a field nobody told you about, found by a test that failed in CI two weeks later.

September 7, 2026
How many tools should an MCP server expose?
Engineering·5 min read

How many tools should an MCP server expose?

Exposing your whole API to an agent makes it worse, not more capable. Tool choice is a selection problem, and every extra option makes the selection harder.

September 6, 2026

A letter when something ships

New SDK languages, changes in the generator, and now and then a longer piece on keeping docs from rotting. Roughly one a month.

Join developers keeping tabs on Octri.

Octri

Upload an OpenAPI spec. Get complete docs and production-ready SDKs in 10 languages, live in minutes.

Contact support

Product

  • API Studio
  • SDK Studio
  • Monitoring
  • MCP Server
  • Pricing
  • Compare
  • Blog
  • Changelog
  • Press Kit

From your spec

  • Spec Audit
  • TypeScript SDK
  • Python SDK
  • Go SDK
  • Java SDK
  • MCP Server

Developers

  • Documentation
  • API Reference
  • SDK Libraries
  • MCP Server
  • Monitoring
  • CLI
  • Support

Legal

  • Terms of Service
  • Privacy Policy
  • Fair Use Policy
  • Data Processing (DPA)
  • Cookie Policy
  • Security
  • Subprocessors

© 2026 Octri, LLC. All rights reserved.

Made by devs who got tired of hand-writing SDKs.