Skip to Content

SDKs

In Depth: Speakeasy vs Stainless

Nolan Sullivan

Nolan Sullivan

February 1, 2026 - 15 min read

In Depth: Speakeasy vs Stainless

In this post, we’ll compare generated SDKs, as well as the underlying philosophies that guide the development of the two companies. And while we acknowledge that our views may be biased, we’ll show our work along with our conclusions so that readers can decide for themselves.

In short: How is Speakeasy different?

OpenAPI-native vs DSL

Speakeasy is OpenAPI-native; Stainless relies on a custom DSL known as the Stainless config . This DSL acts as an intermediary layer between your API spec and the generated SDKs. While Speakeasy also uses a config file (for feature flags), they aren’t a DSL. Your OpenAPI spec remains the primary source of truth for SDK generation.

Speakeasy has also invested heavily in open source OpenAPI tooling , building a best-in-class toolchain for working with OpenAPI that’s useful even outside of Speakeasy.

Being OpenAPI-native is beneficial for integration into an existing stack. Regardless of the API proxies, server-side code, or specific web framework that you’re using, you can plug in the Speakeasy tools. Stainless is doubling down on a vertically integrated approach by building a backend TypeScript framework  which will become the foundation for their solution. Their product will work best when you buy the entire stack; Speakeasy will shine regardless of the other tools in your existing stack.

On-prem and air-gapped deployments

Speakeasy is a standalone CLI binary, so it can run anywhere: on-prem, in a locked-down CI pipeline, or fully air-gapped with zero network egress. Teams can fully eject from the Speakeasy platform and run generation entirely within their own infrastructure. Stainless requires network connectivity to their cloud service for SDK generation, which rules out air-gapped environments and limits deployment flexibility.

CI/CD integration

Because Speakeasy is a simple CLI, it integrates with any CI/CD pipeline — GitHub Actions, GitLab CI, Jenkins, CircleCI, or anything else that can run a binary. Speakeasy provides first-class GitHub Actions workflows out of the box, but teams aren’t locked into them. This flexibility supports complex real-world setups like monorepos with multiple SDK targets, separate pipelines for internal vs public SDKs, and cross-team workflows where API changes automatically trigger SDK regeneration and notify downstream consumers. Stainless is more tightly coupled to its own platform for generation orchestration.

Trusted publishing

Speakeasy supports trusted publishing for TypeScript (npm) and Python (PyPI), so packages can be published directly from CI without storing long-lived secrets. The Speakeasy GitHub Action is fully open source, making it straightforward for enterprises to fork, audit, and adapt it for their own publishing requirements. Multiple enterprise teams have ejected the action into their own infrastructure for custom registry publishing without any friction.

Type-safe vs type-faith

Speakeasy SDKs safely parse server response data to ensure type safety. By contrast, Stainless SDKs essentially slap an any on response data and unsafely cast it to the expected types, providing a false sense of security that code is type-safe. In reality, the code can break unexpectedly as the API evolves.

Forward compatibility

APIs evolve constantly. When the server returns a new enum value or union type that the SDK doesn’t recognize, the way the SDK handles that unknown data is critical. There are three possible approaches:

  1. Safely capture the unknown data into a placeholder type — the SDK preserves the value in a type-safe wrapper like Unrecognized<string> or an UNKNOWN variant, letting your code handle it gracefully
  2. Unsafely cast the data — the SDK slaps types on response data without runtime validation, so unknown values silently pass through and may cause unexpected behavior downstream
  3. Throw an error — the SDK rejects the entire response, crashing your application even though the API returned a valid 200 OK

Speakeasy takes approach #1. Speakeasy SDKs are designed with forward compatibility in mind. Enums are automatically generated as open types with an Unrecognized<string> variant, and discriminated unions include an UNKNOWN variant that preserves the raw payload. This means when an API adds a new enum value or union type, existing SDKs continue working — no crashes, no silent data loss.

Stainless takes approach #2. Stainless SDKs cast response data without runtime validation, so unknown enum values pass through as untyped strings. While this avoids crashes, it provides no type-safe mechanism for handling unknown values, leading to code that may silently break when the API evolves.

This difference is especially important for teams shipping SDKs to external developers who upgrade on their own schedule. Speakeasy’s approach ensures that adding a new enum value or union type to your API never breaks existing SDK consumers. For a deeper dive, see our post on forward-compatible SDKs: strict in development, lax in production.

Customizability

Both platforms support injecting arbitrary custom code into generated SDKs. Speakeasy additionally provides hooks — a structured way to add code into the SDK lifecycle for implementing custom auth schemes, protocols, and other cross-cutting concerns.

Customization approaches

Approach
Arbitrary custom code
Speakeasy
Stainless
Lifecycle hooks
Speakeasy
Stainless

Hooks are isolated from generated code, so they’re guaranteed not to conflict when the SDK is regenerated. This makes them ideal for custom auth schemes, request/response transformations, and other lifecycle logic. Arbitrary code is sometimes the better fit, but it carries a higher likelihood of merge conflicts on regeneration since it lives alongside generated output. Speakeasy’s custom code approach is based on a local git patch system, which makes it much more friendly for AI agent intervention in the codebase — agents can modify custom code regions without needing to understand the full generated output.

Velocity and maturity

Stainless was founded in 2021  and has expanded its language support to seven languages. By comparison, Speakeasy launched in October 2022 and has released support for ten languages in less time. The Speakeasy platform is also broader, with support for additional generation features, like webhooks, React Hooks, and contract testing, not supported by Stainless.

Both companies are financially secure, having raised $25M+ in funding.

Support

Speakeasy provides dedicated Slack channels for direct access to the engineering team. Over the last three months, median response times have been 2.30 minutes (November), 3.02 minutes (December), and 2.57 minutes (January). This level of responsiveness means issues get resolved quickly, often in real time. Stainless offers support through standard channels but without the same level of direct, rapid engagement.

Platform

Platform Comparison

Product
Speakeasy
Stainless
Speakeasy
Stainless
Speakeasy
Stainless
⚠️
CLI Generation
Speakeasy
Stainless
Speakeasy
Stainless
OpenAPI linting & validation
Speakeasy
Stainless

Terraform provider generation

Both Speakeasy and Stainless support Terraform provider generation, but Speakeasy has a significant head start in production adoption. Some of the largest Terraform providers in the ecosystem are generated and maintained with Speakeasy, including Kong, Airbyte, Cribl, Styra, Opal, FireHydrant, ConductorOne, and Etleap. Our team is very deep with Go and Terraform experience including the creator of the Terraform plugin framework.

This track record matters. Terraform providers have strict expectations around stability, resource coverage, and lifecycle management. Speakeasy’s Terraform generation has been battle-tested across hundreds of managed resources and complex API surfaces, giving teams confidence that the generated provider will hold up in production.

SDK generation

SDK Language Support

Language
TypeScript
Speakeasy
Stainless
Python
Speakeasy
Stainless
Go
Speakeasy
Stainless
Java
Speakeasy
Stainless
Kotlin
Speakeasy
Stainless
Ruby
Speakeasy
Stainless
C#
Speakeasy
Stainless
⚠️ incomplete
PHP
Speakeasy
Stainless
⚠️ incomplete
Unity
Speakeasy
Stainless

If there’s a language you require that we don’t support, add it to our roadmap .

SDK features

Breadth matters, but so does the depth of support for each language. The table below shows the current feature support for Speakeasy and Stainless’s SDK generation.

SDK Feature Comparison

Feature
Speakeasy
Stainless
Speakeasy
Stainless
Async functions
Speakeasy
Stainless
Streaming uploads
Speakeasy
Stainless
Custom SDK naming
Speakeasy
Stainless
Speakeasy
Stainless
Custom dependency injection
Speakeasy
Stainless
Speakeasy
Stainless
⚠️ non-OpenAPI standard
Speakeasy
Stainless
Speakeasy
Stainless
Speakeasy
Stainless
❌ (manual)
Field defaults
Speakeasy
Stainless
Speakeasy
✅ type-safe open enums & unions
Stainless
⚠️ untyped passthrough

Pricing

In terms of pricing, both Speakeasy and Stainless offer free plans, as well as paid plans for startups and enterprises. The most significant pricing difference is in the enterprise plan. Existing customers indicate that Stainless’s enterprise pricing is ~20% higher than Speakeasy’s. Of course, this can vary, and we recommend reaching out to both companies for a quote.

Pricing Comparison

Plan
Free
Speakeasy
1 language; max 250 operations
Stainless
Up to 5 SDKs; max 25 endpoints
Starter
Speakeasy
N/A
Stainless
$250/mo per SDK (35% bulk discount)
Business
Speakeasy
$600/mo per language (annual); max 250 operations
Stainless
$800/mo per SDK; max 200 methods
Enterprise
Speakeasy
Custom pricing
Stainless
Custom pricing; unlimited SDKs

Speakeasy vs Stainless: TypeScript SDK comparison

TypeScript SDK Comparison Summary

Aspect
Number of dependencies
Vercel SDK (Speakeasy)
1 (Zod only)
Cloudflare SDK (Stainless)
25+ dependencies
Supported runtimes
Vercel SDK (Speakeasy)
Node.js, Deno, Bun, browsers
Cloudflare SDK (Stainless)
Node.js, Deno, Bun, browsers
Safely casts response data
Vercel SDK (Speakeasy)
✅ Yes
Cloudflare SDK (Stainless)
❌ No
React support
Vercel SDK (Speakeasy)
✅ Built-in hooks
Cloudflare SDK (Stainless)
❌ Manual implementation

SDK structure

Vercel SDK (Speakeasy)

  • README.md
  • package.json
  • tsconfig.json
    • index.ts
    • core.ts

Cloudflare SDK (Stainless)

  • README.md
  • package.json
  • tsconfig.json
    • index.ts
    • core.ts
    • error.ts
    • resource.ts
    • pagination.ts

The Vercel SDK (generated by Speakeasy) maintains a clear separation of concerns with dedicated folders for models, operations, hooks, and comprehensive documentation. Each component and operation has its own file, making the codebase easy to navigate and understand.

The Cloudflare SDK (generated by Stainless) organizes code differently, with a flatter structure under resources and extensive runtime shims for cross-platform compatibility. While this approach supports multiple JavaScript runtimes, it results in more configuration files and less clear separation between different types of code.

Structure affects developer experience. SDK users form their first impressions from the high-level organization, and a well-structured SDK suggests quality and maintainability to developers evaluating whether to adopt it.

Dependencies and bundle size

One key difference between Speakeasy and Stainless approaches is their dependency philosophy, which directly impacts bundle size and security surface area.

Vercel SDK (Speakeasy) - Minimal dependencies

Vercel SDK Dependencies

The Vercel SDK has an extremely minimal dependency graph with only Zod as its single runtime dependency. This focused approach provides:

  • Reduced attack surface: Fewer dependencies mean fewer potential security vulnerabilities
  • Predictable updates: Only one external dependency to monitor and maintain
  • Simplified auditing: Security teams can easily review the entire dependency chain
  • Faster installation: Minimal dependencies result in quicker npm install times

Cloudflare SDK (Stainless) - Complex dependency web

Cloudflare SDK Dependencies

The Cloudflare SDK includes a complex web of 25+ dependencies, creating a more intricate dependency graph with:

  • Larger attack surface: More dependencies increase potential security risks
  • Complex maintenance: Multiple dependencies require ongoing monitoring for vulnerabilities
  • Update complexity: Changes in any dependency can introduce breaking changes
  • Installation overhead: More dependencies mean longer installation times

While the Cloudflare SDK’s dependencies serve specific purposes (cross-platform compatibility, streaming support, etc.), all of that functionality can be achieved with minimal external dependencies as shown by the Speakeasy generated SDK.

Generated types and type safety

Both Speakeasy and Stainless generate TypeScript types, but they differ significantly in their approach to type safety. Speakeasy generates types with runtime validation using Zod, while Stainless relies primarily on compile-time TypeScript checking.

Let’s examine how each handles creating a deployment with project configuration:

vercel-sdk-types.ts
// Vercel SDK (Speakeasy) - with runtime validation import { Vercel } from "@vercel/sdk"; const vercel = new Vercel({ bearerToken: "your-token" }); async function createDeployment() { // Strong typing with runtime validation const deployment = await vercel.deployments.createDeployment({ // !mark // !callout[/}/] Zod validates this at runtime and compile time name: "my-project", gitSource: { type: "github", repo: "user/repo", ref: "main" }, // Missing required fields will cause both // TypeScript errors AND runtime validation errors }); return deployment; }
cloudflare-sdk-types.ts
// Cloudflare SDK (Stainless) - compile-time only import Cloudflare from "cloudflare"; const cf = new Cloudflare({ apiToken: "your-token" }); async function createZone() { // Strong compile-time typing, no runtime validation const params: Cloudflare.ZoneCreateParams = { // !mark // !callout[/}/] Only TypeScript compile-time checking name: "example.com", account: { id: "account-id" } // Invalid data might pass TypeScript but fail at runtime }; const zone = await cf.zones.create(params); return zone; }

The Vercel SDK generates Zod schemas that validate data both at compile time and runtime, catching type errors before they reach the server. The Cloudflare SDK provides excellent TypeScript types but relies on server-side validation to catch runtime errors.

This difference becomes critical when dealing with dynamic data or complex validation rules that can’t be fully expressed in TypeScript’s type system.

Runtime type checking

Speakeasy creates SDKs that are type-safe from development to production. As our CEO wrote, type safe is better than type faith.

The Vercel SDK uses Zod  to validate data sent to and received from the server. This provides safer runtime code execution and helps developers catch errors before making API calls. By contrast, the Cloudflare SDK unsafely casts response data — effectively slapping an any on it and trusting that the shape matches at runtime.

Here’s what happens when invalid data is passed to each SDK:

vercel-runtime-validation.ts
// Vercel SDK (Speakeasy) - Runtime validation import { Vercel } from "@vercel/sdk"; const vercel = new Vercel({ bearerToken: "your-token" }); async function createDeployment() { try { await vercel.deployments.create({ // !mark // !callout[/:/] Zod validation error: Expected string, received number teamId: 12345, // Invalid: should be string gitSource: { type: "github", repo: "user/repo", ref: "main" } }); } catch (error) { // Catches validation error immediately // before making the HTTP request console.log("Validation failed:", error.message); } }
cloudflare-no-validation.ts
// Cloudflare SDK (Stainless) - No runtime validation import Cloudflare from "cloudflare"; const cf = new Cloudflare({ apiToken: "your-token" }); async function updateZone() { try { const params: any = { // Bypassing TypeScript // !mark // !callout[/:/] No runtime validation - sent to server as-is name: 12345, // Invalid: should be string account: { id: "account-id" } }; await cf.zones.create(params); } catch (error) { // Only catches server-side validation errors // after the HTTP request is made console.log("Server error:", error.message); } }

The Vercel SDK catches type errors immediately with Zod validation, providing clear error messages before making HTTP requests. The Cloudflare SDK has no runtime validation — data is unsafely cast and sent over the network as-is, and errors are only discovered when the server rejects the request.

This difference is crucial when dealing with dynamic data, user input, or complex validation rules that can’t be fully expressed in TypeScript’s type system.

Authentication handling

Both SDKs handle authentication, but with different approaches and levels of built-in sophistication.

The Vercel SDK (generated by Speakeasy) uses bearer token authentication with simple configuration. Authentication is handled automatically for all requests, with no additional setup required.

The Cloudflare SDK (generated by Stainless) uses API token authentication and provides comprehensive error handling with specific error classes for different authentication scenarios, including AuthenticationError, PermissionDeniedError, and other HTTP status-specific errors.

When it comes to OAuth 2.0 support, Speakeasy-generated SDKs include built-in OAuth 2.0 client credentials handling with automatic token lifecycle management, retries, and error handling. This means the SDK automatically fetches, stores, and refreshes tokens as needed without requiring additional code.

Stainless-generated SDKs typically require manual OAuth implementation when OAuth is needed, meaning developers must write additional code to handle token acquisition, storage, refresh logic, and error recovery.

MCP server

Both Speakeasy and Stainless allow you to generate an MCP server, which reuses your SDK methods, based on your API. Stainless generates the MCP server by default in the SDK package, which makes the SDK package larger.

At Speakeasy, because we believe in the separation of concerns, we provide the MCP server and the SDK as separate options you can choose to generate or not. This keeps your SDK package lightweight if you don’t need the server functionality. To generate an MCP server, select the Model Context Protocol (MCP) Server option when generating the SDK.

Selecting MCP option

Let’s compare the generated MCP server for both SDKs.

Speakeasy

  • README.md
  • manifest.json
  • package.json
  • eslint.config.mjs
  • tsconfig.json

Stainless

  • jest.config.ts
  • manifest.json
  • package.json
  • README.md
  • tsc-multi.json
  • tsconfig.build.json
  • tsconfig.dist-src.json
  • tsconfig.json
  • yarn.lock

Speakeasy again focuses on simplicity, giving you a simpler file structure with only the parts you need for an MCP server.

Stainless has a more complicated file structure, with more bloat.

Usage

Both platforms let you run MCP servers locally using the setup instructions in the READMEs.

Speakeasy makes distribution easier than Stainless. It creates DXT files that users can drag and drop into Claude Desktop without having to edit configuration files manually. Via Gram  you also get a hosted page for your MCP server that makes it easy to integrate into other MCP clients.

Speakeasy (also through Gram) further provides advanced functionality like curating toolsets for specific use cases, custom tools, prompt refining and production-grade hosting in one click.

Webhooks support

Speakeasy-generated SDKs provide built-in support for webhook validation, payload parsing, and delivery with automatic signature verification using HMAC or other signing algorithms. The generated SDK includes strongly-typed webhook event handlers based on the OpenAPI specification.

The Vercel SDK includes webhook handling capabilities as part of its comprehensive feature set, allowing developers to validate and process webhook events with minimal setup.

Stainless-generated SDKs typically don’t provide out-of-the-box webhook functionality. The Cloudflare SDK focuses primarily on API calls rather than webhook handling, requiring developers to implement their own logic for verifying event signatures, defining event payload types, and managing webhook delivery mechanisms.

This difference means that APIs requiring webhook support benefit significantly from Speakeasy’s built-in webhook validation and type-safe event handling, while Stainless users must build these features manually.

Learn more about how Speakeasy handles webhooks in the webhooks documentation.

React Hooks

React Hooks simplify state and data management in React apps, enabling developers to consume APIs more efficiently. Speakeasy generates built-in React Hooks using TanStack Query . These hooks provide features like intelligent caching, type safety, pagination, and integration with modern React patterns like SSR and Suspense. Stainless does not generate React Hooks.

speakeasy-example/booksView.tsx
import { useQuery } from "@tanstack/react-query"; function BookShelf() { // loads books from an API const { data, status, error } = useQuery( [ "books", // Cache key for the query ], async () => { const response = await fetch("https://api.example.com/books"); return response.json(); }, ); if (status === "loading") return <p>Loading books...</p>; if (status === "error") return <p>Error: {error?.message}</p>; return ( <ul> {data.map((book) => ( <li key={book.id}>{book.title}</li> ))} </ul> ); }

For example, in this basic implementation, the useQuery hook fetches data from an API endpoint. The cache key ensures unique identification of the query. The status variable provides the current state of the query: loading, error, or success. Depending on the query status, the component renders loading, error, or the fetched data as a list.

For an in-depth look at how Speakeasy uses React Hooks, see the React Hooks documentation.

Summary

We’ve all experienced bad SDKs that make integration with the API harder, not easier. Speakeasy is building a generator to make poorly written, poorly maintained SDKs a thing of the past. To do so, our team has put an extraordinary level of thought into getting the details of SDK generation right. We think that the effort has earned us the position to compare favorably with any other generator.

If you are interested in seeing how Speakeasy stacks up against some of the popular open-source SDK-generation tools, check out this post.

Last updated on

Build with
confidence.

Ship what's next.