Configure SDK Options
Configure gen.yaml options for an existing Speakeasy SDK. Supports TypeScript, Python, Go, Java, C#, PHP, and Ruby.
For new SDK projects: Use
skill instead. This skill is for configuring an existing SDK.
Language-Specific Guides
For comprehensive configuration details, see the language-specific guides:
| Language | Guide | Key Features |
|---|
| TypeScript | content/languages/typescript.md | Zod validation, React Query, standalone functions, dual module format |
| Python | content/languages/python.md | Pydantic models, async modes (both/split), uv/poetry support |
| Go | content/languages/go.md | Response formats, interface generation, K8s integration |
| Java | content/languages/java.md | Builder pattern, Gradle customization, Maven Central publishing |
| C# | content/languages/csharp.md | Async/await, cancellation tokens, DI integration, NuGet |
| PHP | content/languages/php.md | Laravel integration, Guzzle config, Packagist publishing |
| Ruby | content/languages/ruby.md | Sorbet typing, Rails integration, RubyGems publishing |
These guides include detailed configuration options, code examples, framework integrations, and publishing instructions.
When to Use
- Configuring language-specific gen.yaml options on an existing SDK
- Setting up SDK hooks, async patterns, or publishing
- Configuring runtime behavior (retries, timeouts, server selection) in application code
- User says: "configure SDK", "gen.yaml options", "SDK config", "runtime override", "per-call config"
- User asks about: Zod, Pydantic, NuGet, PyPI, npm, Maven Central, Packagist, RubyGems
Inputs
| Input | Required | Description |
|---|
| Existing SDK | Yes | SDK with already created |
| Target language | Yes | TypeScript, Python, Go, Java, C#, PHP, or Ruby |
Outputs
| Output | Description |
|---|
| Updated gen.yaml | Language-specific configuration |
| Hook files | Custom hooks if enabled |
Prerequisites
You must have an existing SDK with
. If not, run:
bash
speakeasy quickstart --skip-interactive --output console \
-s openapi.yaml -t <language> -n "MySDK" -p "<package-name>"
Common Configuration (All Languages)
These options apply to all SDK targets in gen.yaml:
yaml
<language>:
version: 1.0.0
packageName: "my-sdk"
# Method signatures
maxMethodParams: 4 # Params before request object
flatteningOrder: parameters-first
# Error handling
responseFormat: flat # or "envelope" (Go)
clientServerStatusCodesAsErrors: true
TypeScript Configuration
yaml
typescript:
version: 1.0.0
packageName: "@myorg/my-sdk"
moduleFormat: dual # esm, commonjs, or dual
zodVersion: v4-mini # v3, v4, or v4-mini
enableCustomCodeRegions: true # For custom code
enableReactQuery: true # React Query hooks
| Feature | Notes |
|---|
| Zod validation | Automatic for all models |
| Tree-shaking | Use + standalone functions |
| JSR publishing | Create , run |
| npm publishing | Standard |
Standalone functions for tree-shaking:
typescript
import { TodoCore } from "my-sdk/core.js";
import { todosCreate } from "my-sdk/funcs/todosCreate.js";
const sdk = new TodoCore({ apiKey: "..." });
Python Configuration
yaml
python:
version: 1.0.0
packageName: "my-sdk"
asyncMode: both # both or split
packageManager: uv # uv or poetry
envVarPrefix: "" # Prefix for env config
| Feature | Notes |
|---|
| Pydantic models | Automatic for all models |
| Async mode | and |
| Async mode | and constructors |
| PyPI publishing | or |
Async patterns:
python
# asyncMode: both (default)
result = sdk.users.list() # sync
result = await sdk.users.list_async() # async
# asyncMode: split
sdk = MySDK() # sync only
async_sdk = AsyncMySDK() # async only
Go Configuration
yaml
go:
version: 0.1.0
packageName: github.com/myorg/my-sdk
maxMethodParams: 2
methodArguments: require-security-and-request
responseFormat: envelope
flattenGlobalSecurity: true
| Feature | Notes |
|---|
| Interfaces | Generate with ifacemaker |
| Mocks | Generate with mockery |
| K8s integration | Add kubebuilder markers, run controller-gen |
Interface generation for testing:
bash
go install github.com/vburenin/ifacemaker@latest
go install github.com/vektra/mockery/v2@latest
ifacemaker --file consumers.go --struct Consumers --iface ConsumersSDK --output consumers_i.go
mockery
Java Configuration
yaml
java:
version: 1.0.0
groupID: com.myorg
artifactID: my-sdk
packageName: com.myorg.mysdk
methodArguments: require-security-and-request
| Feature | Notes |
|---|
| Builder pattern | Automatic for all classes |
| Build customization | Use (preserved) |
| Maven Central | ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository
|
Client usage:
java
MySdk sdk = MySdk.builder()
.security(Security.builder().apiKey("key").build())
.build();
C# Configuration
yaml
csharp:
version: 1.0.0
packageName: MyOrg.MySDK
dotnetVersion: "6.0"
baseErrorName: MySDKException
| Feature | Notes |
|---|
| Async/await | All operations async by default |
| SSE streaming | support |
| NuGet publishing | dotnet pack -c Release && dotnet nuget push
|
Async with cancellation:
csharp
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
var result = await sdk.Users.ListAsync(cancellationToken: cts.Token);
PHP Configuration
yaml
php:
version: 1.0.0
packageName: myorg/my-sdk
namespace: MyOrg\MySDK
| Feature | Notes |
|---|
| PHP 8.2+ | Required minimum version |
| Guzzle | HTTP client (configurable timeout) |
| Packagist | Tag release, register on Packagist.org |
Security callback for token refresh:
php
$sdk = MySDK\MySDK::builder()
->setSecuritySource(fn() => getTokenFromCache() ?? refreshToken())
->build();
Ruby Configuration
yaml
ruby:
version: 1.0.0
packageName: my-sdk
module: MySdk
typingStrategy: sorbet # sorbet or none
| Feature | Notes |
|---|
| Sorbet typing | Optional, enable with |
| Faraday | HTTP client |
| RubyGems | |
SDK Hooks (All Languages)
Enable custom hooks with
enableCustomCodeRegions: true
. Hook files are preserved across regeneration.
| Language | Hook Location |
|---|
| TypeScript | |
| Python | |
| Go | |
| Java | |
| C# | |
| PHP | |
| Ruby | |
See
skill for detailed hook implementation.
Runtime Overrides
Runtime behavior can be configured at SDK instantiation or per-call. These override gen.yaml defaults.
Server Selection
Define server IDs in OpenAPI spec, then select at runtime:
yaml
# OpenAPI spec
servers:
- url: https://api.example.com
x-speakeasy-server-id: production
- url: https://sandbox.example.com
x-speakeasy-server-id: sandbox
| Language | SDK Constructor | Custom URL |
|---|
| TypeScript | new SDK({ server: "sandbox" })
| new SDK({ serverURL: "..." })
|
| Python | | |
| Go | SDK.New(SDK.WithServer("sandbox"))
| |
Retry Overrides
Override retry behavior per-call (spec defaults set via
):
TypeScript:
typescript
const res = await sdk.payments.create({ amount: 1000 }, {
retries: {
strategy: "backoff",
backoff: { initialInterval: 1000, maxInterval: 30000, maxElapsedTime: 120000, exponent: 2.0 },
retryConnectionErrors: true,
},
});
Python:
python
from sdk.utils import BackoffStrategy, RetryConfig
res = sdk.payments.create(amount=1000, retries=RetryConfig("backoff",
backoff=BackoffStrategy(1000, 30000, 120000, 2.0), retry_connection_errors=True))
Go:
go
res, err := sdk.Payments.Create(ctx, req, operations.WithRetries(retry.Config{
Strategy: "backoff", Backoff: &retry.BackoffStrategy{
InitialInterval: 1000, MaxInterval: 30000, MaxElapsedTime: 120000, Exponent: 2.0},
RetryConnectionErrors: true}))
Timeout Overrides
Set global timeout on SDK constructor, or per-call:
| Language | Global | Per-call |
|---|
| TypeScript | new SDK({ timeoutMs: 30000 })
| sdk.op({}, { timeoutMs: 60000 })
|
| Python | | |
| Go | | operations.WithTimeoutMs(60000)
|
Pagination Usage
SDK auto-generates pagination helpers when
is set in spec:
typescript
// Auto-iterate all pages
for await (const user of await sdk.users.list({ limit: 50 })) {
console.log(user.name);
}
// Manual pagination
let page = await sdk.users.list({ limit: 50 });
while (page) {
for (const user of page.data) { console.log(user.name); }
page = await page.next();
}
Decision Framework
| Situation | Action |
|---|
| Need tree-shaking (TS) | Set , use standalone functions |
| Need async/sync (Python) | Set (default) |
| Need separate async client | Set (Python) |
| Need interfaces for testing (Go) | Use ifacemaker + mockery |
| Need custom build config (Java) | Edit |
| Need runtime retry override | Pass config in per-call options |
| Need runtime timeout override | Set on constructor or per-call |
| Need server switching | Use in spec, select at runtime |
What NOT to Do
- Do NOT use this skill for initial SDK generation - use
- Do NOT edit generated files outside custom code regions
- Do NOT modify files in that aren't in preserved directories (hooks, extra)
Troubleshooting
| Language | Issue | Solution |
|---|
| TypeScript | Bundle too large | Use standalone functions |
| Python | Async pagination blocking | Enable fixFlags.asyncPaginationSep2025: true
|
| Go | Interface not generated | Ensure struct is exported (capitalized) |
| Java | Gradle sync fails | Run ./gradlew --refresh-dependencies
|
| C# | Async deadlock | Use not |
| PHP | PHP version error | Requires PHP 8.2+ |
| Ruby | Sorbet errors | Run |
| All | Retries not working | Ensure at document root or operation level |
| All | Server ID not recognized | Add to each server entry |
| All | Pagination undefined | Add to the list operation |
After Making Changes
After modifying gen.yaml configuration, prompt the user to regenerate the SDK:
Configuration complete. Would you like to regenerate the SDK now with
?
If the user confirms, run:
bash
speakeasy run --output console
Changes to gen.yaml only take effect after regeneration.
Related Skills
- - Initial SDK generation
- - Detailed hook implementation
- - Spec customization