SDKs
In Depth: Speakeasy vs Stainless
Nolan Sullivan
February 1, 2026 - 15 min read

NOTE
This comparison of Speakeasy & Stainless reflects the current state of both platforms as of February 2026. Both companies continue to evolve rapidly, particularly around AI-agent integration. If you think we need to update this post, please let us know!
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
Speakeasy has also invested heavily in open source OpenAPI tooling
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
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:
- Safely capture the unknown data into a placeholder type — the SDK preserves the value in a type-safe wrapper like
Unrecognized<string>or anUNKNOWNvariant, letting your code handle it gracefully - 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
- 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
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
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
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
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
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
Speakeasy vs Stainless: TypeScript SDK comparison
NOTE
For this technical comparison, we’ll examine the Cloudflare TypeScript SDK (generated by Stainless) and the Vercel SDK (generated by Speakeasy) to demonstrate real-world differences between these two approaches to SDK generation.
TypeScript SDK Comparison Summary
SDK structure
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

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 installtimes
Cloudflare SDK (Stainless) - Complex dependency web

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 (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 (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 any on it and trusting that the shape matches at runtime.
Here’s what happens when invalid data is passed to each SDK:
// 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 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.

Let’s compare the generated MCP server for both SDKs.
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
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
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.