{} </>
v1.6.1 · MIT License

Forge production-ready SDKs
from OpenAPI specs

The free, open-source OpenAPI 3.x → TypeScript, Go, Rust, and WASM SDK generator. Production-ready clients in 60 seconds — auth, retry, idempotency, validation, SSE, and middleware built in.

For backend & platform teams shipping public APIs who are tired of hand-rolling SDK clients.

TypeScript Go Rust WASM
curl -sSL https://specforge.deepwhaleai.com/install | sh
259 unit tests 4 language targets 4 platforms CI WASM plugin system

Why specforge?

Most OpenAPI generators leave teams building runtime infrastructure by hand. specforge delivers a complete, production-ready SDK — not just types.

vs openapi-generator, swagger-codegen, fern, stainless, speakeasyspecforge
Incomplete types — nullable, oneOf, allOf produce broken or any-typed outputFull composition: allOf merging, oneOf type guards, discriminator mapping, nullable propagation
No runtime — you get types but no client, auth, retry, or error handlingProduction-ready runtime: auth providers, exponential backoff, pagination, middleware, idempotency, SSE streaming
Single language — each generator is a silo with different behaviorOne IR, four targets: TypeScript, Go, Rust, and WASM plugins share the same resolved spec
No validation — generated code trusts the server blindlyRuntime request/response validation catches contract violations in dev and tests
No testing — you write mock servers by handspecforge test generates mock server tests from example responses
No documentation — separate tools for API docsspecforge docs generates a static HTML documentation site
No CI integration — manual diffing and lintingspecforge diff detects breaking changes, specforge check lints specs, GitHub Action for one-line CI
Slow CLI on large specs (multi-minute runs on GitHub / Stripe)12× faster than OpenAPI Generator on real-world specs (1,431-schema Stripe, 965-schema GitHub). See benchmarks.

How It Works

A four-stage pipeline that turns one OpenAPI spec into four production-ready SDKs — with the same auth, retry, and pagination logic across every language.

01 📄
Input
OpenAPI 3.x Spec
YAML or JSON, 3.0 or 3.1. From a file, a URL, or a workspace of versioned specs.
.yaml.json3.0 / 3.1
02 ⚙️
Parse · Resolve
specforge-core
Validates the document, resolves every $ref, merges allOf, and lowers 3.1→3.0 quirks.
resolve $refallOf mergecycle-safe
03 🧬
Language-Neutral
Intermediate Representation
A versioned JSON IR. Every emitter walks the same IR — so behavior is consistent across all targets.
DocumentOperationType
04 🔧
Emit
4 Targets in Parallel
Rayon-parallel file emission to TS, Go, Rust, or WASM plugin SDKs. Deterministic, tree-shakeable.
TSGoRustWASM

Hover any stage above to learn more

Each stage is independent and testable. The IR is documented in assets/ir-schema.json — build custom emitters against it with specforge emit.

terminal · bash
# TypeScript — native fetch, dual ESM/CJS package, tree-shakeable
specforge generate openapi.yaml -o ./sdk-ts -l ts

# Go — stdlib net/http only, zero third-party deps
specforge generate openapi.yaml -o ./sdk-go -l go -n github.com/acme/widget-go

# Rust — reqwest + serde + tokio, async-first
specforge generate openapi.yaml -o ./sdk-rs -l rust -n widget_sdk

# Lint a spec (strict mode treats warnings as errors)
specforge check openapi.yaml --strict

# Detect breaking changes — exit 1 on breaking, perfect for CI gates
specforge diff v1.yaml v2.yaml

Spec Parsing & Resolution

Handles real-world OpenAPI specs at scale — GitHub (~965 schemas / 1209 ops) and Stripe (~1431 / 587).

🔗

OpenAPI 3.0 + 3.1

Handles both spec versions transparently. 3.1 type arrays, $ref siblings, and numeric exclusiveMinimum are auto-converted for parsing.

🧩

Full $ref Resolution

Named types stay named — no exponential inlining blow-ups. Self-referential and mutual $ref cycles are safe by construction.

🏗️

Composition Support

allOf merges properties (last-wins, required union). oneOf/anyOf generate type guards. Discriminator mapping preserved.

📐

Go & Rust Idioms

allOf with one $ref: Go emits embedded structs, Rust emits #[serde(flatten)]. Proper composition, not flat merging.

🎯

Deterministic Output

IndexMap preserves spec order. Same spec + same version = identical output. Bit-stable for caching and diffing.

🔍

Spec Linting

8 configurable rules (duplicate operation IDs, missing descriptions, unused schemas) with .specforge.yaml config.

⚠️

Breaking Change Detection

specforge diff compares two specs: removed operations, new required parameters, type changes. Exit code 1 for CI gates.

🛡️

Production Runtime

Auth providers, exponential backoff, pagination helpers, concurrency control, middleware, idempotency keys, and SSE streaming built-in.

🧬

WASM Plugins

Need Kotlin, Swift, or Python? Build a custom emitter as a WASM plugin with the specforge plugin SDK.

Generated SDK Runtime

Every generated SDK is a complete, production-ready client — not just types. All capabilities available in TypeScript, Go, and Rust.

Client Core
Foundation
5
Typed models & operations strict
Full request/response types with proper optionality — errors caught at compile time, not in production.
Auth providers 3 schemes
Bearer (static + dynamic), API key (header/query), custom providers — swap credentials without touching client code.
Pagination helpers cursor · offset
Walk every page in one call. No manual cursor juggling or off-by-one errors.
oneOf type guards narrowX
Generated isX() / narrowX() helpers to safely narrow union types at runtime.
HTTP client DI mockable
Inject your own fetch, http.Client, or reqwest::Client for testing.
🛡
Resilience
Survives failure
5
Retry w/ jitter full-jitter
Full-jitter exponential backoff. Configurable max retries and retriable status codes (408, 429, 502–504).
Per-attempt timeouts configurable
Set a deadline for each retry attempt — prevents hung requests from blocking your app.
Idempotency keys unsafe only
Auto-generated Idempotency-Key on POST/PUT/PATCH/DELETE — one key per retry loop, safe to replay.
Rate limiting 2 algos
Token bucket and sliding window rate limiters, configurable per-client or per-call.
Response caching ETag
ETag-based caching with TTL expiry and 304 handling — avoid re-fetching unchanged data.
Concurrency & Middleware
Control flow
5
Concurrency semaphore maxConcurrent
Async semaphore limits in-flight requests — prevents overwhelming the API or hitting rate limits.
In-flight dedupe single-flight
Coalesces identical GET/HEAD/OPTIONS — N callers share 1 upstream call and N fresh bodies.
Middleware chain composable
Add logging, tracing, header injection without modifying the generated client.
Interceptors req/res
Request/response body transformers — post-process data without writing middleware.
Structured logging pluggable
Pluggable Logger interface with ConsoleLogger and NoopLogger defaults.
📊
Streaming & Observability
Visibility
4
SSE streaming typed events
Server-Sent Events with proper error handling. Stream events as async iterators across all 3 languages.
Runtime validation opt-in
Validate request/response bodies against the spec. Catch contract violations in dev, not production.
Telemetry hooks metrics
Request metrics, error tracking, cache hit/miss ratios — pipe to Prometheus, OTel, or your backend.
i18n errors 8 locales
Localized error messages (en, es, fr, de, ja, zh, pt, it) via --locale flag at generate time.

Language Highlights

Each generated SDK is a standalone project — no shared runtime dependency, no version coupling.

app.ts
import { createClient, bearerAuth, streamSse } from "./sdk/src/index.ts";

const client = createClient({
  baseUrl: "https://api.example.com",
  auth: bearerAuth(() => process.env.API_TOKEN!),
  maxConcurrent: 8,
  dedupe: true,
  idempotency: true,
  retry: { maxRetries: 3 },
});

// Typed request & response — no `any`
const page = await client.pets.listPets({ limit: 20 });

// SSE streaming with proper error handling
const res = await client.request("GET", "/events");
for await (const ev of streamSse(res)) {
  console.log(ev.event, ev.data);
}

Dual ESM/CJS package, native fetch — zero runtime dependencies. Discriminated union error types, isX()/narrowX() type guards for oneOf, per-model validate functions.

main.go
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "time"

    sdk "github.com/acme/widget-go"
)

func main() {
    c := sdk.NewClient().
        WithBaseURL("https://api.example.com").
        WithBearerToken(os.Getenv("API_TOKEN")).
        WithTimeout(10 * time.Second).
        WithMaxConcurrent(8).
        WithDedupe(true).
        WithIdempotency(true).
        WithRetry(sdk.DefaultRetryOptions())

    // Middleware for logging & tracing
    c.Use(func(ctx context.Context, req *sdk.MiddlewareRequest,
        next func(context.Context, *sdk.MiddlewareRequest) (*sdk.MiddlewareResponse, error),
    ) (*sdk.MiddlewareResponse, error) {
        start := time.Now()
        res, err := next(ctx, req)
        log.Printf("%s %s %v", req.Method, req.URL, time.Since(start))
        return res, err
    })

    pets, err := c.ListPets(context.Background(), 20)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(pets)
}

Stdlib only (net/http, encoding/json) — zero third-party dependencies. Embedded structs for allOf, New{Union} helpers for discriminated oneOf deserialization.

main.rs
use std::time::Duration;
use widget_sdk::{api, Client};
use widget_sdk::streaming::SseStream;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::builder()
        .base_url("https://api.example.com")
        .bearer_token(std::env::var("API_TOKEN")?)
        .timeout(Duration::from_secs(10))
        .max_concurrent(8)
        .dedupe(true)
        .idempotency(true)
        .build()?;

    // Fully typed request/response
    let pets = api::list_pets(&client, Some(20)).await?;

    // SSE streaming
    let res = client
        .request_stream(reqwest::Method::GET, "/events", &[], None)
        .await?;
    let mut sse = SseStream::new(res.bytes_stream());
    while let Some(ev) = sse.next_event().await? {
        println!("{}: {}", ev.event, ev.data);
    }

    Ok(())
}

reqwest + serde + tokio async. #[serde(flatten)] for allOf, discriminant() for oneOf, SseStream for SSE parsing over bytes_stream().

CLI Commands

One binary, 27+ commands. Cross-compiled for Linux, macOS, and Windows. Use specforge <cmd> --help for full flags.

specforge — v1.6.1
~/projects/api-sdk
Core5
You'll use these every day
generatespecforge generate <spec> -o <dir> -l ts|go|rust -n <name>
checkspecforge check <spec> --strict --disable <rule>
diffspecforge diff <old.yaml> <new.yaml> --breaking-only
emitspecforge emit <spec> --stream | --schema
profilespecforge generate <spec> --profile
Validation & CI5
Lint, security, and CI gates
securityspecforge security <spec> --format text|json|md
analyzespecforge analyze <spec>
graphspecforge graph <spec> --format mermaid|dot
migratespecforge migrate <old.yaml> <new.yaml> -o guide.md
verifyspecforge verify <spec> --url <base_url>
Docs, Mock & Test4
Ship testable docs and mocks
docsspecforge docs <spec> -o ./docs
testspecforge test <spec> -l ts|go|rust -o ./tests
mockspecforge mock <spec> --port 3000
demospecforge demo -o ./demo.yaml
Workspace6
Multi-spec and version handling
initspecforge init <dir>
convertspecforge convert <spec> --to 3.0|3.1
mergespecforge merge <a.yaml> <b.yaml> -o merged.yaml
versionspecforge version <spec> --mode url|header|query
versionsspecforge versions <dir>
workspacespecforge workspace .specforge.yaml
Ecosystem7
Plugins, marketplace, and history
pluginspecforge plugin install|list|remove <name>
marketspecforge market list|search|info|add
exportspecforge export <spec> -o swagger.json
evolutionspecforge evolution <dir> --since main
dashboardspecforge dashboard <spec> -o ./dash
inferspecforge infer <sample.json> -o openapi.yaml
changelogspecforge changelog <spec> --since v1.0.0
⎯ no commands match

Installation

Pick your platform. Run one command. You'll have specforge generating SDKs in under a minute.

~/projects
# Download the latest Linux release (~7 MB)
curl -sSL https://github.com/amafjarkasi/specforge-openapi-sdk-codegen/releases/latest/download/specforge-linux-amd64 -o specforge

# Make it executable and install
chmod +x specforge
sudo mv specforge /usr/local/bin/

# For ARM64 (Raspberry Pi, Graviton, etc.):
# download specforge-linux-arm64 instead

# ✓ specforge is now on your $PATH
# Apple Silicon (M1/M2/M3)
curl -sSL https://github.com/amafjarkasi/specforge-openapi-sdk-codegen/releases/latest/download/specforge-darwin-arm64 -o specforge
chmod +x specforge
sudo mv specforge /usr/local/bin/

# Intel Macs:
# download specforge-darwin-amd64 instead

# macOS may quarantine the binary — strip it first:
xattr -d com.apple.quarantine /usr/local/bin/specforge

# ✓ specforge is now on your $PATH
# PowerShell — Windows 10/11 (x64)
Invoke-WebRequest -Uri "https://github.com/amafjarkasi/specforge-openapi-sdk-codegen/releases/latest/download/specforge-windows-amd64.exe" -OutFile "specforge.exe"

# Move it somewhere on your $env:PATH
Move-Item specforge.exe C:\Windows\System32\

# Or use Scoop:
scoop install specforge

# ✓ specforge is now on your PATH
# Requires Rust 1.75+ — get it at rustup.rs
git clone https://github.com/amafjarkasi/specforge-openapi-sdk-codegen.git
cd specforge-openapi-sdk-codegen

# Build and install the CLI (~2 min, cached after)
cargo install --path crates/specforge-cli --locked

# ✓ specforge is now on your $PATH
# .github/workflows/sdk.yml name: Generate SDK on: [push] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: amafjarkasi/specforge-openapi-sdk-codegen@v1 with: spec: openapi.yaml lang: ts out: ./sdk - uses: actions/upload-artifact@v4 with: name: sdk path: ./sdk
Verify your install
specforge --version # → specforge 1.6.1
Star us on GitHub

Quick Start

Build the CLI and generate your first SDK in under 2 minutes.

terminal
# 1. Build
git clone https://github.com/amafjarkasi/specforge-openapi-sdk-codegen
cd specforge-openapi-sdk-codegen
cargo build -p specforge-cli

# 2. Generate a TypeScript SDK
./target/debug/specforge generate fixtures/petstore.yaml -l ts -o ./sdk-ts

# 3. Lint a spec
./target/debug/specforge check fixtures/petstore.yaml

# 4. Check for breaking changes
./target/debug/specforge diff openapi-v1.yaml openapi-v2.yaml

Battle-Tested at Scale

specforge handles real-world specs from the world's largest APIs — no toy examples required.

1,431
Schemas Parsed
Stripe API (full)
587
Operations
Stripe API (full)
2.3s
Full SDK Generated
Stripe → TypeScript
965
Schemas Parsed
GitHub API (full)

12× Faster than OpenAPI Generator

Parallel IR resolution, zero JVM overhead. Rust-native speed.

🎯

Zero Runtime Dependencies

Generated TS SDKs use native fetch only. No axios, no node-fetch, no surprises.

🛡️

Full Type Safety

oneOf, allOf, anyOf, discriminator — all resolved correctly. No any leaks.

🔌

One Spec, Four Languages

Same IR powers TypeScript, Go, Rust, and WASM emitters. Consistency guaranteed.

VS Code Extension

Full IDE integration with 23+ commands. Generate, validate, diff, and analyze specs without leaving your editor.

One-Click Generation

Pick your language and output directory. SDK generated in seconds.

Auto-Validate on Save

Configurable spec validation every time you save. Catch errors early.

Keyboard Shortcuts

Ctrl+Shift+G to generate, Ctrl+Shift+K to check. Fast and ergonomic.

🔍

Context Menus

Right-click any spec file for quick access to all commands.

📊

Status Bar Integration

Quick access to mock server and spec status at a glance.

🔄

Progress Notifications

Real-time feedback for long-running operations.

Spec Marketplace

18 curated specs from the world's most popular APIs. Generate SDKs instantly with real-world schemas.

GitHub
965 schemas, 1209 operations
Stripe
1431 schemas, 587 operations
Kubernetes
Full K8s API coverage
Spotify
Web API for music apps
Notion
Pages, databases, and blocks
Okta
Identity and access management
Figma
Design file API
Twilio
SMS, voice, and video APIs

Plus 10 more: Atlassian, Bitbucket, Vercel, Netlify, CircleCI, Slack, Discord, Linear, Jira, and Confluence.

specforge market list

MIT Licensed. Optional Paid Plans.

The specforge CLI is MIT licensed — use it, fork it, ship it, no strings. Optional paid plans add commercial warranty, private registry, hosted docs, and team features.

Open Source CLI
Free · MIT
Full CLI under MIT. Use in commercial, internal, and personal projects — royalty-free. Source on GitHub.
  • All 22 CLI commands
  • TypeScript, Go, Rust emitters
  • WASM plugin SDK
  • Community support
  • Private & non-commercial use
Enterprise
Custom
For API-first companies with 50+ internal APIs.
  • Self-hosted or dedicated cloud
  • SSO / SAML
  • Audit trail & compliance
  • Custom emitter development
  • SLA & priority support
  • Design partner program

Get Early Access

Cloud Pro launching Q1 2027. Join the waitlist — first 100 teams get founding member pricing locked for life.

No spam. Just launch updates and early access.