< Go back

Type-Safe APIs in 2026: From tRPC to OpenAPI Generators to End-to-End Inference

27/5/2026 · 10 min read

The API boundary is the contract two halves of your product agree to keep — and in 2026 the question is no longer "should it be type-safe" but "how strict should the type safety be, and who pays the cost".

For most of the last decade the type-safe API conversation in the TypeScript world has been dominated by tRPC. It demonstrated, convincingly and at scale, that you can have end-to-end type inference without a separate schema file, a code generator, or a build step. For a generation of full-stack teams that argument settled the question.

But "settled" is doing a lot of work in that sentence. As products grew past the single Next.js codebase — mobile clients, other languages, external partners, public APIs — the cracks in pure inference showed up, and the OpenAPI generator ecosystem quietly closed most of the ergonomic gap that originally made tRPC so attractive. The 2026 picture is messier and more interesting than the binary tRPC-vs-OpenAPI debate of three years ago.

Three Strategies, Three Different Assumptions

The choices teams actually make in 2026 cluster into three strategies. They are not interchangeable — each one optimises for a different assumption about who else will consume the API and how much trust there is between the client and the server.

1. End-to-end inference (tRPC, Hono RPC, ts-rest's "type-only" mode)

One TypeScript codebase. The client imports the type of the server router. No schema file, no generator, no build step. Renames in the server propagate to the client at compile time. This is the gold standard of developer ergonomics when the client and the server are owned by the same team in the same repo.

2. Schema-first with code generation (OpenAPI + openapi-typescript, ts-rest's "contract" mode, GraphQL Codegen)

A single source of truth — an OpenAPI YAML, a ts-rest contract, a GraphQL schema — generates both server stubs and client types. The schema is a real artefact you can publish, version, give to partners, and run a linter against. This is the right answer the moment more than one client consumes the API or more than one language is involved.

3. Runtime-validated REST with Zod or Valibot at both ends

The boring strategy. Plain REST endpoints, Zod schemas defining request and response bodies, with the same schemas shared via a packages workspace. No magic, no generator, no proprietary protocol — just two halves of the codebase agreeing on the shape of the data, validated at the wire and in TypeScript. This is the strategy that ages best.

Where tRPC Still Wins (And Where It Stopped Winning)

tRPC is not dead — far from it. For a single-team, single-codebase Next.js product where the API will never be consumed by anyone other than your own client, it is still the fastest path from idea to typed endpoint. The compile-time feedback loop is unmatched, and the cost of a rename is genuinely zero.

The places it stopped winning are also clear. If a mobile app written in Swift or Kotlin is going to consume the API, you cannot import a TypeScript router type into a Swift codebase. If a partner needs API access, you cannot ship them a tarball of your router types. If your engineering org has a public API as a product, you need an OpenAPI spec for the docs, the SDKs and the partner integrations — and once you have that spec, having tRPC alongside it doubles the surface area.

The honest 2026 framing is that tRPC is the right answer for the early-stage, single-client product, and the wrong answer the moment the API becomes a contract with anyone outside the codebase. Many teams I have seen would have saved themselves a quarter of migration work if they had made that call at the start, rather than after the API grew beyond their first React app.

The OpenAPI Generator Ecosystem Quietly Caught Up

The OpenAPI experience in 2023 was painful — heavy generators, ugly client code, manual schema maintenance, and a brittle feedback loop. Most of those rough edges have been sanded down in the last two years, and the toolchain has converged on something that genuinely competes with tRPC on developer experience.

  • openapi-typescript and openapi-fetch give you a generated client that is a thin wrapper around fetch, with typed paths, params, request bodies and responses, and zero runtime overhead. The generated code is small enough to read.
  • ts-rest and Zodios let you author the contract in TypeScript with Zod schemas, and emit the OpenAPI spec from that contract. You get the best of both: a single source of truth in code and a real spec for the parts of the world that need one.
  • Hono's RPC mode, Effect/Schema, and TypeBox give you Zod-equivalent runtime validation with smaller bundles and OpenAPI emission. The performance gap with plain Zod has closed enough that the choice is now ergonomic, not performance-driven.
  • The Stainless and Speakeasy SDK generators turn an OpenAPI spec into polished, idiomatic clients in Python, Go, Ruby, Java, Swift and Kotlin. The "generated SDK" no longer looks generated. For any team shipping a public API, this is the unlock.

End-to-End Inference Beyond TypeScript

The interesting frontier in 2026 is not "TypeScript end-to-end inference" — that problem is solved — but end-to-end inference across language boundaries. A typed contract in TypeScript that produces equivalent typed clients in Swift, Kotlin, Python and Go, without a manual schema-to-types-to-SDK pipeline at every step.

The serious attempts at this in 2026 fall into three camps. The first is the Stainless / Speakeasy approach — generate everything from OpenAPI, treat the spec as the contract, accept the small ergonomic tax of maintaining a schema. This is the boring, scalable answer and it is what most production teams ship today.

The second is the gRPC and Protobuf revival, quietly powered by Connect — a modern gRPC-over-HTTP toolchain that handles the worst parts of the original spec and gives you generated clients in every language that matters. It is overkill for a SaaS CRUD app but the right answer for high-throughput internal services where the boundary crosses teams and languages.

The third is the more experimental Edge-RPC and Effect Schema-driven approaches, where the contract is authored in one language and reflected into others via a shared interchange format. These are exciting but still niche; most teams are better served by the boring option for the next year or two.

Runtime Validation Is The Part Teams Skip

Compile-time types tell you what the code expects. Runtime validation tells you what the wire actually delivered. The gap between those two is where production incidents live, and it is the part teams under-invest in until the first 500 from a malformed request takes down a critical flow.

The 2026 default should be: every API endpoint validates its request body with a runtime schema, and the same schema generates the TypeScript type the handler uses. Zod, Valibot, ArkType, Effect Schema and TypeBox all do this well; pick one and use it consistently. The cost is a few extra lines per endpoint; the payoff is that the type system and the runtime stop being two different worlds.

Response validation is the more contentious half. Validating outgoing responses catches bugs in your own code but adds latency to every request. The pragmatic compromise is to validate in development and staging environments, sample in production, and use the schema for documentation and SDK generation rather than as a runtime checker on every response. The "validate everything everywhere" purist position rarely survives the first performance review.

Versioning Is Where All Of This Either Pays Off Or Falls Apart

Type safety solves "is this call shaped correctly today". It does not solve "is this call still shaped correctly six months from now, after the API has shipped three non-breaking-but-actually-breaking changes". Versioning is the part nobody wants to design up-front and everybody wishes they had.

The strategies I see working in 2026 all share a pattern. The contract is versioned at the route level, not the API level — POST /v2/orders rather than a global v2 namespace. Old versions are kept alive long enough for clients to upgrade, with a deprecation header and a sunset date in the response. Breaking changes require a new path; additive changes ship under the existing one. The schema artefact (OpenAPI, ts-rest contract, GraphQL schema) is checked into the repo and diffed in pull requests, so any change to the contract is visible at code review time.

The teams that get this wrong fall into one of two failure modes. Either they never version anything and every client is stuck on the latest, breaking on every deploy. Or they version everything aggressively and end up maintaining five versions of every endpoint, paying that tax forever. The right answer is in the middle, and it requires a contract artefact you can actually diff. End-to-end inference alone does not give you that diff.

Picking A Strategy For Your Team And Product

Here is the heuristic I use when teams ask me which strategy to pick. It is not a clean decision tree because the question is genuinely shaped by your product, but the shape of the answer falls out of a few honest questions.

If you are a single team shipping a single Next.js app to a single client, and you do not expect that to change in the next year, tRPC or Hono RPC is the fastest path and the right default. Do not over-engineer.

If you have a mobile client, multiple frontends, partner integrations, or a public API on the roadmap, start with ts-rest or an OpenAPI-first approach. The migration cost from tRPC to OpenAPI later is real, and it always happens at the worst time.

If you are a platform company shipping SDKs in multiple languages, OpenAPI plus a generator like Stainless or Speakeasy is the only answer that scales. The contract becomes a published artefact and the SDKs become a feature of the product, not an afterthought.

If your internal services need to communicate across language boundaries with real performance requirements, Connect-over-Protobuf is worth the steeper learning curve. The wire format pays you back in throughput and the contract pays you back in cross-language type safety.

Conclusion: The Contract Is The Product

The thing you are actually building when you design an API is a contract between two halves of a system. Type safety is just the tool that keeps that contract honest as both halves change underneath it.

The 2026 winners in this space did not pick one strategy and evangelise it. They picked the strategy that matched their product shape and their team shape, and invested in the unglamorous parts — schemas in the repo, validation at the boundary, versioned routes, generated SDKs, diffable contracts in pull requests. The strategy is less interesting than the discipline around it.

If you take one thing from this, take this: end-to-end inference is amazing, and it is also a trap if you confuse "the types line up" with "the contract is sound". A contract is a thing you can publish, diff, version and ship to people outside your codebase. Types alone are not that thing. Pick the lightest strategy that gives you a real contract for your actual consumers, and resist the temptation to ship anything heavier until the product asks for it.

Next article

Designing Evals →

Designing an API surface that has to last?

Contact me