Skip to content

Validated at runtime, not just typed at compile time.

Generate types, a fetch client, React Query hooks, and Zod schemas from one spec. Opt into Zod and the generated client validates every request and response body at runtime, so bad data fails at the boundary, not three components deep.
Installnpm install -D openapi-zod-ts

Tested against 128 real-world specs (Stripe, GitHub, Spotify, OpenAI) in CI on every commit.

openapi-zod-ts npm versionopenapi-react-query npm versionMIT license

Real output from the Petstore 3.0 spec, generated by the toolchain and committed to the repo. This is what CI compiles on every PR.

// client.ts: auto-generated by openapi-zod-ts
import type { Pet, Order } from './models.js'
import { getConfig, type ClientConfig } from './client-config.js'
import { z } from 'zod'
import { PetSchema, OrderSchema } from './schemas.js'
export class ApiError extends Error {
constructor(
public readonly status: number,
public readonly body: unknown
) {
super(`API error ${status}`)
this.name = 'ApiError'
}
}
// Validates both request and response bodies at runtime against Zod schemas.
export async function addPet(body: Pet, config?: Partial<ClientConfig>): Promise<Pet> {
PetSchema.parse(body)
const res = await _request('POST', '/pet', { body }, config)
return PetSchema.parse(await res.json())
}
export async function findPetsByStatus(
params: { status: 'available' | 'pending' | 'sold' },
config?: Partial<ClientConfig>
): Promise<Pet[]> {
const searchParams = new URLSearchParams()
if (params?.status != null) searchParams.set('status', String(params.status))
const res = await _request('GET', '/pet/findByStatus', { searchParams }, config)
return z.array(PetSchema).parse(await res.json())
}

Generates clean, type-safe code from real-world specs like:

  • Stripe
  • GitHub
  • Spotify
  • OpenAI
  • Adyen
  • + 123 more in CI

Each package is independent, but they compose. A single OpenAPI spec drives everything from server contract to form field error UX.

The CodeWithAgents OpenAPI package pipelineAn OpenAPI spec feeds openapi-zod-ts, which produces TypeScript types, Zod schemas, and a fetch client. The fetch client feeds openapi-react-query for React Query hooks and openapi-server for a typed service interface and router. api-errors is a runtime package that maps any API error shape to form field errors.OpenAPI specopenapi-zod-tsTypeScript typesmodels.tsZod schemasyours to extendFetch clientclient.tsopenapi-react-queryReact Query v5 hooksopenapi-serverservice interface + routerapi-errorsRuntime, no codegen. Maps any API error shape to form fields.

One source of truth. When the spec changes, re-run the generators and the compiler tells you exactly what broke.


openapi-zod-ts

Types, fetch client, and Zod schemas from your OpenAPI spec. Learn more

@codewithagents/openapi-react-query

React Query v5 hooks, generated. Learn more

@codewithagents/openapi-server

Typed service interface plus an optional router (default: none) for Fastify, Hono, or Express. Learn more

@codewithagents/openapi-msw

Generate MSW v2 HTTP handlers with seeded Faker mock data from your OpenAPI spec. Learn more

@codewithagents/api-errors

Map API errors to form field errors. Learn more


Validated, not just typed

Generate Zod schemas from your spec, then enable runtime validation with one config field (input_schema). The fetch client checks both request and response bodies against your schemas, so bugs surface at the boundary, not deep in your UI.

Proven on 128 real specs

Stripe, GitHub, Spotify, OpenAI, Adyen, AWS, and more. Every spec is generated and compiled in CI on every commit. Not benchmarked once and forgotten.

Code you own

Output is plain TypeScript files in your repo. No runtime black box, no proprietary client to call into. Adjust, extend, delete. The compiler is your upgrade guide.

OpenAPI 3.1 first-class

Full support for $ref, allOf, anyOf, oneOf, nullable, and 3.1.1 keyword changes. 3.0.x is supported in practice: 8 of our 13 showcase specs are 3.0.x and all compile. nullable: true is normalized to the 3.1 T | null form, so 3.0 nullable fields produce the correct types. A few 3.0-only constructs are still being normalized. No Swagger 2.0.

Native fetch. Zero added bundle weight.

The generated client uses only native fetch. No axios, no wrapper libraries. Nothing from the codegen packages ends up in your bundle.

ESM, strict mode, Prettier-ready

Every generated file compiles with strict: true and "type": "module". Output passes prettier --check with your own config.


  1. Install the generator.

    Terminal window
    npm install -D openapi-zod-ts

    For React Query hooks, also add:

    Terminal window
    npm install -D @codewithagents/openapi-react-query && npm install @tanstack/react-query
  2. Create a config file in your project root.

    {
    "input_openapi": "./openapi.json",
    "output": "./src/api"
    }

    Point input_openapi at your spec (JSON or YAML, local path or URL). The output directory is created automatically.

  3. Run the generator and import the output.

    Terminal window
    npx openapi-zod-ts

    Then use the generated barrel directly:

    import { configureClient, getPetById, useFindPetsByStatus } from './src/api'
    configureClient({ baseUrl: 'https://petstore3.swagger.io/api/v3' })
    const pet = await getPetById('1')
    const { data, isLoading } = useFindPetsByStatus({ status: 'available' })



GitHub

Source code, issues, and the compatibility matrix across 128 specs. View on GitHub