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 9, 2026·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.

#sdks#api-design#developer-experience#openapi
Should you hand-write your SDKs or generate them?

The case for hand-writing is better than generation advocates admit, and it has a shape.

A hand-written client can be idiomatic in ways a generator cannot reach. It can name a method after what your users call the thing rather than after your operationId. It can collapse three endpoints into one convenience call because that is how the workflow actually goes. It can have a helper that does the retry-and-poll dance your API requires and your spec does not describe.

If you ship one language, your API changes a few times a year, and you have someone who cares about that library, hand-writing produces a better artifact. That is the honest version.

The problem is that almost nobody stays in that situation.

What actually breaks it

Two variables, and they multiply.

Languages. One library is a craft project. Six is a maintenance obligation, and the sixth is always the one nobody on the team writes daily. Your Rust SDK gets written by whoever was free, and it gets updated at whatever rate that person has time for.

Change rate. An API that changes monthly means every change lands six times. Miss one and you have SDKs that disagree about what your API does, which is worse than having fewer SDKs.

Multiply them and you get the failure everyone recognises: the TypeScript client is current because that is what the team uses, Python is one version behind, and Ruby has an open issue from March saying a field is missing.

The 2026 drift data puts numbers on the pressure. 41% of APIs see schema drift within thirty days, and 86% of those events are field additions, which are exactly the changes nobody remembers to propagate because nothing breaks when you skip them. Six hand-written clients means six chances to skip.

What generation is actually good at

Not the method names. The parts nobody enjoys writing and everybody gets subtly wrong on the fifth language:

Consistency across languages. One retry policy, one pagination contract, one auth mechanism, emitted six times. Teams that hand-write six clients write six retry policies, and by year two they disagree about which status codes are safe to repeat.

The unglamorous correctness. Backoff with jitter, per-attempt timeouts, idempotency keys on writes, typed errors split by cause. Every client needs these and hand-written ones acquire them incrementally after incidents.

Keeping up. A field added to a response appears in every language on the next generation, without anyone remembering.

Reaching languages you do not staff. You probably do not have a Dart developer. Your Flutter users still want a client.

What generation is bad at, and what to do about it

This is the part worth being straight about, because it is where the objection lives.

Generated names can be bad. They come from your operationIds, and if those were written for a linter rather than a call site you get client.actions.actionsActionsGet(). The fix is not to hand-write the client, it is to fix the ids or override the generated method name per endpoint. Both are cheaper than maintaining a library.

Generators do not know your workflows. If using your API means "create, then poll until ready, then fetch", no generator will produce the helper that does it. That helper is real value and it has to be written.

Generated code can be ugly. Sometimes true, and it matters less than people think because most consumers read the method signature and the types, not the transport layer.

The synthesis most teams land on is the useful one: generate the client, hand-write a thin layer of workflow helpers on top of it. The generated part tracks your API automatically and the hand-written part is small enough that one person can own it in every language you care about. You get idiom where idiom matters and coverage everywhere else.

The decision, plainly

Hand-write if you ship one or two languages, your API is stable, and someone owns the library as part of their job rather than as an occasional errand.

Generate if you ship three or more languages, or your API changes more than quarterly, or you want to support a language nobody on your team writes.

Generate plus a helper layer if your API has multi-step workflows worth wrapping, which is most APIs past a certain size.

The crossover is lower than instinct suggests, because the cost of a hand-written SDK is not the writing. It is the year of small updates afterwards, paid in the languages you are least equipped to maintain.

The question that settles it

Ask what happens the next time you add a required parameter to an endpoint.

If the answer is "I update the spec and every client regenerates", you are fine. If it is "I update the spec, then open six repositories", you already know which of the six will be late, and your users will find out before you do.

If you want to see what generated output actually looks like before deciding, the OpenAPI to TypeScript SDK, Python, Go and Java pages show the call site each one produces from the same document, including the default client shape and what you can change about it.

And whichever way you decide, the spec audit is worth running first, because a document that scores badly produces a bad generated client and a hand-written one built on the same missing schemas will have the same gaps, only hidden behind code somebody wrote.

← PreviousGetting your API docs cited when someone asks an AI about your product
Next →API-first in practice: what changes when the spec is the source of truth

Related articles

What counts as a breaking change when your SDK is generated
Engineering·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.

September 11, 2026
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
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.