sdk-tf-generation-best-practices
sdk-tf-generation-best-practices
Comprehensive best-practices reference for generating SDKs and Terraform providers with Speakeasy. Covers the full lifecycle: OpenAPI spec preparation, code-first extraction, generation workflows, language-specific guides, customization, and testing.
When to Use
- Generating an SDK from an OpenAPI spec
- Generating a Terraform provider from an OpenAPI spec
- Generating an MCP server from an OpenAPI spec
- Extracting an OpenAPI spec from existing code (FastAPI, Flask, Django, Spring Boot, NestJS, Hono, Rails, Laravel)
- Customizing SDK generation (hooks, auth, error handling, retries, pagination)
- Fixing OpenAPI validation errors or applying overlays
- Testing generated SDKs (integration, contract, Arazzo)
- Understanding language-specific SDK patterns (TypeScript, Python, Go, Java, C#, Ruby, PHP)
- Upgrading or bumping the Speakeasy CLI version in workflow.yaml
- Regenerating an SDK after spec or version changes
- Customizing SDK README documentation
- Adding examples to an OpenAPI spec via overlays
- Testing generated SDK endpoints
- User says: "generate SDK", "regenerate SDK", "update SDK", "SDK best practices", "terraform provider", "generate MCP server", "SDK customization", "SDK testing", "test my SDK", "upgrade speakeasy", "bump version", "SDK readme", "SDK documentation", "add examples to spec"
How to Use
This skill contains detailed guides in the content/ subdirectory relative to this file. Read the specific guide for the user's task rather than trying to answer from this index alone.
These guides are also accessible via the Speakeasy CLI:
speakeasy agent context [path]
To find the right guide, use the routing table below or the decision tree.
Quick Routing Table
What are you trying to do?
| Goal | Start Here |
|---|---|
| Generate an SDK from an OpenAPI spec | content/plans/sdk-generation.md |
| Generate a Terraform provider | content/plans/tf-provider-generation.md |
| Extract OpenAPI from existing code | content/code-first/[framework].md |
| Fix OpenAPI validation errors | content/spec-first/validation.md |
| Customize SDK generation | content/sdk-customization/ |
| Generate multiple SDK variants (Azure, GCP, etc.) | content/sdk-customization/multi-target-sdks.md |
| Set up a multi-SDK monorepo | content/plans/sdk-generation.md#advanced-multi-sdk-monorepos |
| Use overlay recipes (open enums, global headers) | content/spec-first/overlays.md#overlay-recipes |
| Use multi-overlay workflows | content/spec-first/overlays.md#multi-overlay-workflow-patterns |
| Track overlay changes with metadata | content/spec-first/overlays.md#overlay-metadata-tracking |
| Implement custom security (HMAC, signatures) | content/spec-first/overlays.md#custom-security-schemes-via-overlay |
| Add SDK hooks (user-agent, telemetry) | content/sdk-customization/hooks.md |
| Implement HTTP signature authentication | content/sdk-customization/hooks.md#custom-security-hook-http-signature-authentication |
| Configure SDK retries, timeouts, pagination | content/sdk-customization/runtime-configuration.md |
| Configure SDK authentication and security | content/sdk-customization/authentication-config.md |
| Customize SDK error handling | content/sdk-customization/error-handling.md |
| Persist custom code changes across regenerations | content/sdk-customization/custom-code.md |
| Generate MCP server for AI assistants | content/sdk-customization/mcp-server.md |
| Orchestrate multi-repo SDK generation | content/sdk-customization/multi-repo-workflows.md |
| Understand SDK language specifics | content/sdk-languages/[language].md |
| Add custom utilities to Python SDKs | content/sdk-languages/python.md#extending-the-sdk-with-sidecar-utilities |
| Publish Java SDK to Maven Central | content/sdk-languages/java.md#maven-central-publishing |
| Add custom code to TypeScript SDKs | content/sdk-languages/typescript.md#custom-code-regions |
| Publish TypeScript SDK to JSR (Deno) | content/sdk-languages/typescript.md#jsr-deno-publishing |
| Configure Ruby SDK with Sorbet typing | content/sdk-languages/ruby.md#sorbet-type-checking |
| Publish Ruby SDK to RubyGems | content/sdk-languages/ruby.md#rubygems-publishing |
| Configure PHP SDK with Laravel integration | content/sdk-languages/php.md#laravel-integration |
| Publish PHP SDK to Packagist | content/sdk-languages/php.md#publishing-to-packagist |
| Generate Go SDK with interfaces for testing | content/sdk-languages/go.md#interface-generation |
| Use Go SDK in Kubernetes operators | content/sdk-languages/go.md#kubernetes-operator-integration |
| Set up SDK integration tests | content/sdk-testing/integration-testing.md |
| Configure Arazzo API testing | content/sdk-testing/arazzo-testing.md |
| Disable tests for specific endpoints | content/sdk-testing/arazzo-testing.md#disabling-tests-via-overlay |
| Run AI-powered contract tests | content/sdk-testing/contract-testing.md |
| Fix ResponseValidationError at runtime | content/sdk-testing/contract-testing.md |
| Validate spec matches live API | content/spec-first/validation.md#dynamic-validation-contract-testing |
| Upgrade Speakeasy version in workflow.yaml | content/plans/sdk-generation.md#version-management |
| Bump pinned speakeasyVersion to latest | content/plans/sdk-generation.md#version-management |
| Regenerate SDK after spec or version change | content/plans/sdk-generation.md |
| Customize SDK README with documentation | content/sdk-customization/readme-customization.md |
| Add branding, examples, or guides to SDK README | content/sdk-customization/readme-customization.md |
| Add examples to OpenAPI spec via overlay | content/spec-first/overlays.md#add-examples |
| Add API-response-based examples to spec | content/spec-first/overlays.md#add-examples |
| Test SDK against live API | content/sdk-testing/integration-testing.md |
| Run contract tests for generated SDK | content/sdk-testing/contract-testing.md |
Directory Structure
content/
├── INDEX.md # This index (SKILL.md)
├── plans/ # Decision trees for workflows
│ ├── sdk-generation.md # Full SDK generation workflow
│ └── tf-provider-generation.md
├── code-first/ # Extract OpenAPI from code
│ ├── fastapi.md
│ ├── flask.md
│ ├── django.md
│ ├── spring-boot.md
│ ├── nestjs.md
│ ├── hono.md
│ ├── rails.md
│ └── laravel.md
├── spec-first/ # OpenAPI validation and fixes
│ ├── validation.md
│ ├── overlays.md # OpenAPI overlays and recipes
│ ├── security-schemes.md
│ ├── pagination.md
│ └── schemas.md
├── sdk-languages/ # Language-specific SDK guides
│ ├── python.md
│ ├── typescript.md # TS: code regions, extra modules, Zod
│ ├── go.md # Go: hooks, interfaces, mocks, K8s
│ ├── java.md
│ ├── csharp.md
│ ├── ruby.md # Ruby: Sorbet typing, RubyGems publishing
│ └── php.md
├── sdk-customization/ # Cross-language SDK customization
│ ├── hooks.md # SDK hooks (UA, telemetry, custom security)
│ ├── runtime-configuration.md # Retries, timeouts, pagination, servers
│ ├── authentication-config.md # Global/per-op security, env vars
│ ├── error-handling.md # Custom error classes and schemas
│ ├── custom-code.md # Persist changes across regenerations
│ ├── multi-target-sdks.md # Multiple variants from one repo
│ ├── multi-repo-workflows.md # Cross-repo SDK orchestration (CI/CD)
│ ├── mcp-server.md # MCP server for AI assistant integration
│ └── readme-customization.md # SDK README branding
├── sdk-testing/ # SDK testing patterns
│ ├── integration-testing.md # Integration test infrastructure
│ ├── arazzo-testing.md # Arazzo API testing format
│ └── contract-testing.md # AI-powered contract testing
├── terraform/ # Terraform provider specifics
│ ├── crud-mapping.md
│ ├── customization.md
│ ├── testing-guide.md
│ └── publishing.md
└── CLI_REFERENCE.md # Canonical CLI command documentation
Decision Tree: Where to Start
START
│
├─ Do you have an OpenAPI/Swagger spec?
│ │
│ ├─ YES ──► Is the spec valid?
│ │ │
│ │ ├─ YES ──► What do you want to generate?
│ │ │ │
│ │ │ ├─ SDK ──► plans/sdk-generation.md
│ │ │ └─ Terraform Provider ──► plans/tf-provider-generation.md
│ │ │
│ │ └─ NO/UNSURE ──► spec-first/validation.md
│ │
│ └─ NO ──► Do you have API code?
│ │
│ ├─ YES ──► What framework?
│ │ ├─ FastAPI ──► code-first/fastapi.md
│ │ ├─ Flask ──► code-first/flask.md
│ │ ├─ Django ──► code-first/django.md
│ │ ├─ Spring Boot ──► code-first/spring-boot.md
│ │ ├─ NestJS ──► code-first/nestjs.md
│ │ ├─ Hono ──► code-first/hono.md
│ │ ├─ Rails ──► code-first/rails.md
│ │ └─ Laravel ──► code-first/laravel.md
│ │
│ └─ NO ──► Cannot proceed without spec or code
Troubleshooting Tree
PROBLEM
│
├─ Getting ResponseValidationError at runtime?
│ │
│ └─ SDK types don't match server responses
│ ├─ Run contract tests to identify all mismatches
│ │ → sdk-testing/contract-testing.md
│ └─ Fix spec or create overlay to correct types
│ → spec-first/validation.md#dynamic-validation-contract-testing
│
├─ SDK doesn't match live API behavior?
│ │
│ ├─ Spec may have drifted from API
│ │ → Run contract tests to detect drift
│ │ sdk-testing/contract-testing.md
│ │
│ └─ Third-party spec may be inaccurate
│ → Validate with contract testing before trusting
│ sdk-testing/contract-testing.md
│
├─ Type mismatch errors in generated SDK?
│ │
│ ├─ At compile time ──► Check spec schema definitions
│ │ spec-first/validation.md
│ │
│ └─ At runtime ──► Server returns unexpected types
│ → Contract testing required
│ sdk-testing/contract-testing.md
│
└─ Enum value not recognized?
│
└─ API returned value not in spec enum
├─ Add missing value to spec/overlay
│ → spec-first/overlays.md
└─ Or use open enums for anti-fragility
→ spec-first/overlays.md#overlay-recipes
Working with Large OpenAPI Documents
OpenAPI specs can be thousands of lines. Do not load the full spec into context. Use yq (YAML) or jq (JSON) to extract only the sections you need.
# List all paths
yq '.paths | keys' spec.yaml
# Inspect a specific endpoint
yq '.paths["/users/{id}"]' spec.yaml
# List all schema names
yq '.components.schemas | keys' spec.yaml
# Inspect a specific schema
yq '.components.schemas.User' spec.yaml
# Check server URLs
yq '.servers' spec.yaml
# List all operationIds
yq '[.paths[][].operationId // empty] | unique' spec.yaml
# For JSON specs, use jq
jq '.paths | keys' spec.json
jq '.components.schemas.User' spec.json
Note: If
yq/jqaren't available, use targetedgrepsearches instead of copying the full spec into context:grep -n 'operationId:' spec.yaml grep -n 'x-speakeasy-entity' spec.yaml
Common Workflows
Workflow A: First-Time SDK Generation
- Read
content/plans/sdk-generation.md - Run
speakeasy quickstart --skip-interactive --output console -s spec.yaml -t python -o ./sdk - SDK generated in output directory
Workflow B: Existing Codebase → SDK
- Identify framework in
content/code-first/ - Extract OpenAPI spec
- Validate with
speakeasy lint openapi --non-interactive -s spec.yaml - Fix issues using
content/spec-first/guides - Generate SDK via
content/plans/sdk-generation.md
Workflow C: SDK Customization
- Ensure
gen.yamlexists (from quickstart) - Read
content/sdk-customization/guides - Modify
gen.yaml - Regenerate with
speakeasy run -y --output console
Workflow D: Multi-Target SDK (Azure, GCP, etc.)
- Read
content/sdk-customization/multi-target-sdks.md - Configure multiple sources in
workflow.yaml - Set up target outputs to
packages/subdirectories - Create CI workflows per target
Workflow E: SDK Extensions (Hooks, Custom Methods)
- For persistent changes anywhere →
content/sdk-customization/custom-code.md - For cross-cutting concerns →
content/sdk-customization/hooks.md - For predefined extension points →
content/sdk-languages/typescript.md#custom-code-regions - For complex logic →
content/sdk-languages/typescript.md#extra-modules-pattern
Workflow F: Upgrade and Regenerate
- Check current
speakeasyVersionin.speakeasy/workflow.yaml - Update
speakeasyVersiontolatestor a specific version →content/plans/sdk-generation.md#version-management - Regenerate with
speakeasy run→content/plans/sdk-generation.md - Test the regenerated SDK →
content/sdk-testing/integration-testing.mdorcontent/sdk-testing/contract-testing.md - Commit changes
Essential CLI Commands
| Command | Purpose |
|---|---|
speakeasy quickstart --skip-interactive --output console -s spec.yaml -t python -o ./sdk |
Non-interactive SDK setup |
speakeasy run -y --output console |
Regenerate SDK from gen.yaml |
speakeasy lint openapi --non-interactive -s spec.yaml |
Validate OpenAPI spec |
speakeasy auth login |
Authenticate with Speakeasy |
Getting Help
- Authentication issues: Run
speakeasy auth login - Validation errors: See
content/spec-first/validation.md - Unsupported feature: Check language guide in
content/sdk-languages/ - CLI errors: See
content/CLI_REFERENCE.mdor runspeakeasy --help
Providing Feedback
If you encounter missing documentation, unclear instructions, or incorrect examples in this agent context, submit feedback directly:
# General feedback
speakeasy agent feedback -m "Description of the issue or suggestion"
# Feedback about a specific document
speakeasy agent feedback -m "Description of the issue" --context-path "path/to/document.md"
Feedback helps improve these documents for all agents. Submit feedback when:
- A guide is missing steps needed to complete a task
- An example does not work as documented
- A CLI command behaves differently than described
- You cannot find documentation for a supported feature
Related Skills
start-new-sdk-project- Quick interactive setup withspeakeasy quickstartregenerate-sdk- Re-run generation after config changesvalidate-openapi-spec- Lint and validate OpenAPI specsdiagnose-generation-failure- Troubleshoot failed generation runscreate-openapi-overlay- Create overlays for spec customizationfix-validation-errors-with-overlays- Fix lint errors with overlays