● v0.6.0 · MIT License

SpecForge

Forge production-ready typed client SDKs from OpenAPI 3.x specs.
One language-neutral IR. Emitters for TypeScript, Go, Rust, and WASM.

TypeScript Go Rust WASM
View on GitHub → Quick Start ↓
123+ unit tests 3 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.

Problem with other generatorsSpecForge's answer
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

How It Works

Parse once, emit many. A language-neutral IR decouples parsing from code generation.

📄OpenAPI 3.xYAML / JSON
⚙️specforge-coreparse · resolve
language-neutral IR
🔧EmittersTS · Go · Rust · WASM
typed client + runtime
# TypeScript cargo build -p specforge-cli ./target/debug/specforge generate openapi.yaml -o ./sdk-ts -l ts # Go ./specforge generate openapi.yaml -o ./sdk-go -l go -n github.com/acme/widget-go # Rust ./specforge generate openapi.yaml -o ./sdk-rs -l rust -n widget_sdk

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.

Generated SDK Runtime

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

Typed models + operations
Auth providers (Bearer, API key, custom)
Retry — full-jitter exponential backoff
Per-attempt timeouts
Pagination helpers (cursor & offset)
Concurrency semaphore (maxConcurrent)
In-flight request deduplication
Composable middleware chain
Idempotency keys on unsafe methods
SSE streaming with error handling
Runtime request/response validation
oneOf type guards (isX / narrowX)

Language Highlights

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

TS

TypeScript

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

Go

Go

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

RS

Rust

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

WASM

WASM Plugins

Build custom emitters in any language. Plugin SDK provides Plugin trait and export_plugin! macro. Compile to wasm32-wasi and run with specforge.

CLI Commands

One binary, eight commands. Cross-compiled for Linux, macOS, and Windows.

specforge generate
Generate an SDK from an OpenAPI spec
specforge check
Lint and validate a spec with configurable rules
specforge diff
Compare two specs and report breaking changes
specforge emit
Dump the resolved IR as JSON (for external tools)
specforge init
Scaffold a new OpenAPI spec with a /health endpoint
specforge convert
Convert between OpenAPI 3.0 and 3.1
specforge docs
Generate a static HTML API documentation site
specforge test
Generate mock server tests from spec examples

Quick Start

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

# 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