# Technical Documentation: hey-api/openapi-ts

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/hey-api/openapi-ts)

### Overview (`README.md`)

<div align="center">
  <img alt="Hey API" height="214" src="https://heyapi.dev/assets/.gen/hey-api-hero-640w.png" width="438">
  <h1><b>Hey API</b></h1>
  <p><em>"OpenAPI codegen that just works."</em><br/><sub>— Guillermo Rauch, CEO of Vercel</sub></p>
</div>

<p align="center">
  <a href="https://www.devtrends.dev/trends?c=v1.kZIBIg"><img src="https://api.devtrends.dev/badge/npm/%40hey-api%2Fopenapi-ts?period=month&style=flat&view=value" alt="DevTrends badge for @hey-api/openapi-ts" /></a>
  <a href="https://www.devtrends.dev/trends?c=v1.kZIBIg&v=change"><img src="https://api.devtrends.dev/badge/npm/%40hey-api%2Fopenapi-ts?period=year&style=flat&view=change" alt="DevTrends badge for @hey-api/openapi-ts" /></a>
  <a href="https://github.com/hey-api/hey-api/actions?query=branch%3Amain"><img src="https://github.com/hey-api/hey-api/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI status" /></a>
  <a href="https://github.com/hey-api/hey-api"><img src="https://img.shields.io/github/stars/hey-api/hey-api?style=flat&logo=github&label=GitHub&color=54C82D" alt="GitHub stars" /></a>
  <a href="https://github.com/hey-api/hey-api/blob/main/LICENSE"><img src="https://img.shields.io/github/license/hey-api/hey-api" alt="MIT License"></a>
</p>

<p align="center">
  <a href="https://heyapi.dev/docs/openapi/typescript/get-started">Manual</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://github.com/hey-api/hey-api/issues">Issues</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://heyapi.dev/docs/openapi/typescript/community/contributing">Contribute</a>
</p>

## About

Hey API is an ecosystem for turning API specifications into production-ready code. It's trusted by thousands of companies – from YC startups to Fortune 500 enterprises – and powers products used by millions worldwide.

This is the monorepo containing all open source Hey API packages. For package-specific documentation and quick start guides, see the individual repositories below.

## Packages

<table>
  <tr>
    <th width="30%">Package</th>
    <th>Description</th>
  </tr>
  <tr>
    <td>
      <a href="packages/openapi-ts"><code>openapi-ts</code></a>
    </td>
    <td>
      TypeScript code generator with 20+ plugins for SDKs, Zod schemas, TanStack Query hooks, and more.
      <br/>
      <a href="https://heyapi.dev/docs/openapi/typescript/get-started">Manual</a>
      <span>&nbsp;•&nbsp;</span>
      <a href="https://npmjs.com/package/@hey-api/openapi-ts">npm</a>
    </td>
  </tr>
  <tr>
    <td>
      <a href="packages/openapi-python"><code>openapi-python</code></a>
    </td>
    <td>
      Python code generator for SDKs and Pydantic models.
      <br/>
      <a href="https://heyapi.dev/docs/openapi/python/get-started">Manual</a>
      <span>&nbsp;•&nbsp;</span>
      <a href="https://npmjs.com/package/@hey-api/openapi-python">npm</a>
    </td>
  </tr>
</table>

## Highlights

- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugins for SDKs
- HTTP clients for Fetch API, Axios, Angular, Next.js, Nuxt, HTTPX, and more
- Zod schemas, TanStack Query hooks, Pydantic models, and 20+ plugins to reduce third-party boilerplate
- highly customizable via plugins

## Libraries

<table>
  <tr>
    <th width="30%">Package</th>
    <th>Description</th>
  </tr>
  <tr>
    <td>
      <a href="packages/spec-types"><code>spec-types</code></a>
    </td>
    <td>
      TypeScript definitions for OpenAPI and JSON Schema specifications with complete inline documentation.
      <br/>
      <a href="https://npmjs.com/package/@hey-api/spec-types">npm</a>
    </td>
  </tr>
</table>



## Contributing

Want to see your code in products used by millions?

Start with our [Contributing](https://heyapi.dev/docs/openapi/typescript/community/contributing) guide and release your first feature.





## Sponsors

Partners behind the future of API tooling. [Become a sponsor](https://heyapi.dev/sponsors).

<h3 align="center">Gold</h3>

<table align="center">
  <tbody>
      <td align="center" width="50%">
        <p></p>
        <p>
          <a href="https://kutt.to/QM9Q2N" target="_blank">
            <picture height="50px">
              <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/opencode/logo-light.svg">
              <img alt="Opencode logo" height="50px" src="https://heyapi.dev/assets/opencode/logo-dark.svg">
            </picture>
          </a>
          <br/>
          The open source coding agent.
          <br/>
          <a href="https://kutt.to/QM9Q2N" style="text-decoration:none;" target="_blank">
            opencode.ai
          </a>
        </p>
        <p></p>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Silver</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/Dr9GuW" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/fastapi/logo-light.svg">
            <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/assets/fastapi/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/Dr9GuW" style="text-decoration:none;" target="_blank">
          fastapi.tiangolo.com
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/yZVkdV" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/brands/unblocked/logo-light.svg">
            <img alt="Unblocked logo" height="40px" src="https://heyapi.dev/assets/brands/unblocked/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/yZVkdV" style="text-decoration:none;" target="_blank">
          getunblocked.com
        </a>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Bronze</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/YpaKsX" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-dark-480w.webp">
            <img alt="Kinde logo" height="34px" src="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-480w.jpeg">
          </picture>
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/HW4GYR" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/photon/logo-light.svg">
            <img alt="Photon logo" height="34px" src="https://heyapi.dev/assets/photon/logo-dark.svg">
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>




## License

Released under the [MIT License](https://github.com/hey-api/hey-api/blob/main/LICENSE).

---

### Overview (`.changeset/README.md`)

# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

---

### Overview (`examples/README.md`)

# Examples

This directory contains integration examples demonstrating how to use `@hey-api/openapi-ts` with various frameworks, libraries, and client implementations.

## Available Examples

- **openapi-ts-angular** - Angular integration with common HTTP client
- **openapi-ts-angular-common** - Angular with @angular/common/http
- **openapi-ts-axios** - Using Axios client
- **openapi-ts-fastify** - Fastify server integration
- **openapi-ts-fetch** - Native Fetch API client
- **openapi-ts-next** - Next.js integration
- **openapi-ts-nuxt** - Nuxt.js integration with plugin
- **openapi-ts-ofetch** - Using ofetch client
- **openapi-ts-openai** - OpenAI API integration
- **openapi-ts-pinia-colada** - Vue with Pinia Colada state management
- **openapi-ts-sample** - Sample/template example (excluded from CI)
- **openapi-ts-tanstack-angular-query-experimental** - Angular with TanStack Query
- **openapi-ts-tanstack-react-query** - React with TanStack Query
- **openapi-ts-tanstack-svelte-query** - Svelte with TanStack Query
- **openapi-ts-tanstack-vue-query** - Vue with TanStack Query

## Generated Code

All examples (except `openapi-ts-sample`) contain generated client code that is **committed to the repository**. This ensures:

1. Examples always reflect the current state of the code generator
2. Changes to the code generator are visible in pull requests
3. CI can verify that examples are kept up-to-date

## Regenerating Examples

After making changes to the core packages, regenerate all example code:

```bash
pnpm examples:update
```

This command will run `openapi-ts` for each example that has an `openapi-ts` script in its `package.json`.

## Verifying Examples

To check if all examples are up-to-date with the current codebase:

```bash
pnpm examples:check
```

This check is also run automatically in CI. If it fails, run `pnpm examples:update` and commit the changes.

## Running Examples

Each example can be run individually using the `example` script:

```bash
# Run dev server for fetch example
pnpm example fetch dev

# Build fetch example
pnpm example fetch build
```

Or directly using pnpm filters:

```bash
pnpm --filter @example/openapi-ts-fetch dev
```

## Creating New Examples

When creating a new example:

1. Create a new directory in `examples/`
2. Add an `openapi-ts` script to `package.json`
3. Run `pnpm examples:update` to create initial generated code
4. Commit both the source and generated code
5. The example will automatically be included in CI checks

## Excluding Examples

To exclude an example from CI (like `openapi-ts-sample`):

1. Remove the `openapi-ts` script from `package.json`, or
2. Update the exclusion filters in `package.json` scripts and `.github/workflows/ci.yml`

---

### Overview (`examples/openapi-ts-angular-common/README.md`)

# Angular

This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.15.

## Development server

To start a local development server, run:

```bash
ng serve
```

Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.

## Code scaffolding

Angular CLI includes powerful code scaffolding tools. To generate a new component, run:

```bash
ng generate component component-name
```

For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:

```bash
ng generate --help
```

## Building

To build the project run:

```bash
ng build
```

This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.

## Running unit tests

To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:

```bash
ng test
```

## Running end-to-end tests

For end-to-end (e2e) testing, run:

```bash
ng e2e
```

Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.

## Additional Resources

For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.

---

### Overview (`examples/openapi-ts-angular/README.md`)

# Angular

This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.15.

## Development server

To start a local development server, run:

```bash
ng serve
```

Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.

## Code scaffolding

Angular CLI includes powerful code scaffolding tools. To generate a new component, run:

```bash
ng generate component component-name
```

For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:

```bash
ng generate --help
```

## Building

To build the project run:

```bash
ng build
```

This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.

## Running unit tests

To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:

```bash
ng test
```

## Running end-to-end tests

For end-to-end (e2e) testing, run:

```bash
ng e2e
```

Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.

## Additional Resources

For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.

---

### Overview (`examples/openapi-ts-next/README.md`)

This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

---

### Overview (`examples/openapi-ts-nuxt/README.md`)

# Nuxt Minimal Starter

Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.

## Setup

Make sure to install dependencies:

```bash
# npm
npm install

# pnpm
pnpm install

# yarn
yarn install

# bun
bun install
```

## Development Server

Start the development server on `http://localhost:3000`:

```bash
# npm
npm run dev

# pnpm
pnpm dev

# yarn
yarn dev

# bun
bun run dev
```

## Production

Build the application for production:

```bash
# npm
npm run build

# pnpm
pnpm build

# yarn
yarn build

# bun
bun run build
```

Locally preview production build:

```bash
# npm
npm run preview

# pnpm
pnpm preview

# yarn
yarn preview

# bun
bun run preview
```

Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.

---

### Overview (`examples/openapi-ts-pinia-colada/README.md`)

# @hey-api/openapi-ts with Pinia Colada Example

This example demonstrates how to use @hey-api/openapi-ts with Pinia Colada for Vue 3 applications.

## Recommended IDE Setup

[VSCode](https://code.visualstudio.com) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).

## Type Support for `.vue` Imports in TS

TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.

## Customize configuration

See [Vite Configuration Reference](https://vitejs.dev/config).

## Project Setup

```sh
pnpm install
```

### Compile and Hot-Reload for Development

```sh
pnpm dev
```

### Type-Check, Compile and Minify for Production

```sh
pnpm build
```

### Run Unit Tests with [Vitest](https://vitest.dev)

```sh
pnpm test:unit
```

---

### Overview (`examples/openapi-ts-tanstack-angular-query-experimental/README.md`)

# OpenapiTsTanstackAngularQueryExperimental

This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 18.2.7.

## Development server

Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files.

## Code scaffolding

Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.

## Build

Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.

## Running unit tests

Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).

## Running end-to-end tests

Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities.

## Further help

To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.

---

### Overview (`examples/openapi-ts-tanstack-svelte-query/README.md`)

# create-svelte

Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).

## Creating a project

If you're seeing this, you've probably already done this step. Congrats!

```bash
# create a new project in the current directory
npm create svelte@latest

# create a new project in my-app
npm create svelte@latest my-app
```

## Developing

Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:

```bash
npm run dev

# or start the server and open the app in a new browser tab
npm run dev -- --open
```

## Building

To create a production version of your app:

```bash
npm run build
```

You can preview the production build with `npm run preview`.

> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.

---

### Overview (`examples/openapi-ts-tanstack-vue-query/README.md`)

# vue-project

This template should help get you started developing with Vue 3 in Vite.

## Recommended IDE Setup

[VSCode](https://code.visualstudio.com) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).

## Type Support for `.vue` Imports in TS

TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.

## Customize configuration

See [Vite Configuration Reference](https://vitejs.dev/config).

## Project Setup

```sh
pnpm install
```

### Compile and Hot-Reload for Development

```sh
pnpm dev
```

### Type-Check, Compile and Minify for Production

```sh
pnpm build
```

### Run Unit Tests with [Vitest](https://vitest.dev)

```sh
pnpm test:unit
```

---

### Overview (`packages/codegen-core/README.md`)

<div align="center">
  <h1 align="center"><b>Codegen Core</b></h1>
  <p align="center">🧱 TypeScript framework for generating files.</p>
</div>

<br/>

<p align="center">
  <a href="https://opensource.org/license/mit" rel="nofollow"><img src="https://img.shields.io/github/license/hey-api/hey-api" alt="MIT License"></a>
  <a href="https://github.com/hey-api/hey-api/actions?query=branch%3Amain"><img src="https://github.com/hey-api/hey-api/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI status" /></a>
</p>

## Notice

This is an internal framework. Visit [Hey API](https://heyapi.dev/) to discover our products.



## Contributing

Want to see your code in products used by millions?

Start with our [Contributing](https://heyapi.dev/docs/openapi/typescript/community/contributing) guide and release your first feature.





## Sponsors

Partners behind the future of API tooling. [Become a sponsor](https://heyapi.dev/sponsors).

<h3 align="center">Gold</h3>

<table align="center">
  <tbody>
      <td align="center" width="50%">
        <p></p>
        <p>
          <a href="https://kutt.to/QM9Q2N" target="_blank">
            <picture height="50px">
              <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/opencode/logo-light.svg">
              <img alt="Opencode logo" height="50px" src="https://heyapi.dev/assets/opencode/logo-dark.svg">
            </picture>
          </a>
          <br/>
          The open source coding agent.
          <br/>
          <a href="https://kutt.to/QM9Q2N" style="text-decoration:none;" target="_blank">
            opencode.ai
          </a>
        </p>
        <p></p>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Silver</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/Dr9GuW" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/fastapi/logo-light.svg">
            <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/assets/fastapi/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/Dr9GuW" style="text-decoration:none;" target="_blank">
          fastapi.tiangolo.com
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/yZVkdV" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/brands/unblocked/logo-light.svg">
            <img alt="Unblocked logo" height="40px" src="https://heyapi.dev/assets/brands/unblocked/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/yZVkdV" style="text-decoration:none;" target="_blank">
          getunblocked.com
        </a>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Bronze</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/YpaKsX" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-dark-480w.webp">
            <img alt="Kinde logo" height="34px" src="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-480w.jpeg">
          </picture>
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/HW4GYR" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/photon/logo-light.svg">
            <img alt="Photon logo" height="34px" src="https://heyapi.dev/assets/photon/logo-dark.svg">
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>




## License

Released under the [MIT License](https://github.com/hey-api/hey-api/blob/main/LICENSE).

---

### Overview (`packages/json-schema-ref-parser/README.md`)

# JSON Schema $Ref Parser

#### Parse, Resolve, and Dereference JSON Schema $ref pointers

## Installation

Install using [npm](https://docs.npmjs.com/about-npm/):

```bash
npm install @hey-api/json-schema-ref-parser
pnpm add @hey-api/json-schema-ref-parser
yarn add @hey-api/json-schema-ref-parser
bun add @hey-api/json-schema-ref-parser
```

## The Problem:

You've got a JSON Schema with `$ref` pointers to other files and/or URLs. Maybe you know all the referenced files ahead
of time. Maybe you don't. Maybe some are local files, and others are remote URLs. Maybe they are a mix of JSON and YAML
format. Maybe some of the files contain cross-references to each other.

```json
{
  "definitions": {
    "person": {
      // references an external file
      "$ref": "schemas/people/Bruce-Wayne.json"
    },
    "place": {
      // references a sub-schema in an external file
      "$ref": "schemas/places.yaml#/definitions/Gotham-City"
    },
    "thing": {
      // references a URL
      "$ref": "http://wayne-enterprises.com/things/batmobile"
    },
    "color": {
      // references a value in an external file via an internal reference
      "$ref": "#/definitions/thing/properties/colors/black-as-the-night"
    }
  }
}
```

## The Solution:

JSON Schema $Ref Parser is a full [JSON Reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03)
and [JSON Pointer](https://tools.ietf.org/html/rfc6901) implementation that crawls even the most
complex [JSON Schemas](http://json-schema.org/latest/json-schema-core.html) and gives you simple, straightforward
JavaScript objects.

- Use **JSON** or **YAML** schemas &mdash; or even a mix of both!
- Supports `$ref` pointers to external files and URLs, as well as custom sources such as databases
- Can bundle multiple files into a single schema that only has _internal_ `$ref` pointers
- Can dereference your schema, producing a plain-old JavaScript object that's easy to work with
- Supports circular references, nested references,
  back-references, and cross-references between files
- Maintains object reference equality &mdash; `$ref` pointers to the same value always resolve to the same object
  instance
- Compatible with Node LTS and beyond, and all major web browsers on Windows, Mac, and Linux

### New in this fork (@hey-api)

- **Multiple inputs with `bundleMany`**: Merge and bundle several OpenAPI/JSON Schema inputs (files, URLs, or raw objects) into a single schema. Components are prefixed to avoid name collisions, paths are namespaced on conflict, and `$ref`s are rewritten accordingly.

```javascript
import { $RefParser } from '@hey-api/json-schema-ref-parser';

const parser = new $RefParser();
const merged = await parser.bundleMany({
  pathOrUrlOrSchemas: [
    './specs/a.yaml',
    'https://example.com/b.yaml',
    { openapi: '3.1.0', info: { title: 'Inline' }, paths: {} },
  ],
});

// merged.components.* will contain prefixed names like a_<name>, b_<name>, etc.
```

- **Dereference hooks**: Fine-tune dereferencing with `excludedPathMatcher(path) => boolean` to skip subpaths and `onDereference(path, value, parent, parentPropName)` to observe replacements.

```javascript
const parser = new $RefParser();
parser.options.dereference.excludedPathMatcher = (p) => p.includes('/example/');
parser.options.dereference.onDereference = (p, v) => {
  // inspect p / v as needed
};
await parser.dereference({ pathOrUrlOrSchema: './openapi.yaml' });
```

- **Smart input resolution**: You can pass a file path, URL, or raw schema object. If a raw schema includes `$id`, it is used as the base URL for resolving relative `$ref`s.

```javascript
await new $RefParser().bundle({
  pathOrUrlOrSchema: {
    $id: 'https://api.example.com/openapi.json',
    openapi: '3.1.0',
    paths: {
      '/ping': { get: { responses: { 200: { description: 'ok' } } } },
    },
  },
});
```



## Contributing

Want to see your code in products used by millions?

Start with our [Contributing](https://heyapi.dev/docs/openapi/typescript/community/contributing) guide and release your first feature.





## Sponsors

Partners behind the future of API tooling. [Become a sponsor](https://heyapi.dev/sponsors).

<h3 align="center">Gold</h3>

<table align="center">
  <tbody>
      <td align="center" width="50%">
        <p></p>
        <p>
          <a href="https://kutt.to/QM9Q2N" target="_blank">
            <picture height="50px">
              <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/opencode/logo-light.svg">
              <img alt="Opencode logo" height="50px" src="https://heyapi.dev/assets/opencode/logo-dark.svg">
            </picture>
          </a>
          <br/>
          The open source coding agent.
          <br/>
          <a href="https://kutt.to/QM9Q2N" style="text-decoration:none;" target="_blank">
            opencode.ai
          </a>
        </p>
        <p></p>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Silver</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/Dr9GuW" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/fastapi/logo-light.svg">
            <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/assets/fastapi/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/Dr9GuW" style="text-decoration:none;" target="_blank">
          fastapi.tiangolo.com
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/yZVkdV" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/brands/unblocked/logo-light.svg">
            <img alt="Unblocked logo" height="40px" src="https://heyapi.dev/assets/brands/unblocked/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/yZVkdV" style="text-decoration:none;" target="_blank">
          getunblocked.com
        </a>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Bronze</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/YpaKsX" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-dark-480w.webp">
            <img alt="Kinde logo" height="34px" src="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-480w.jpeg">
          </picture>
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/HW4GYR" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/photon/logo-light.svg">
            <img alt="Photon logo" height="34px" src="https://heyapi.dev/assets/photon/logo-dark.svg">
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>




## License

Released under the [MIT License](https://github.com/hey-api/hey-api/blob/main/LICENSE).

---

### Overview (`packages/nuxt/README.md`)

<div align="center">
  <img alt="Hey API logo" height="150" src="https://heyapi.dev/assets/.gen/logo-astronaut-300w.png" width="150">
  <h1 align="center"><b>Nuxt Module</b></h1>
  <p align="center">🚀 Nuxt module for <code>@hey-api/openapi-ts</code> codegen.</p>
</div>




## Features

- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output
- [platform](https://heyapi.dev/docs/openapi/typescript/integrations) for automating codegen builds

## Dashboard

Access your projects and OpenAPI specifications in the [Hey API Platform](https://app.heyapi.dev/).



## Contributing

Want to see your code in products used by millions?

Start with our [Contributing](https://heyapi.dev/docs/openapi/typescript/community/contributing) guide and release your first feature.



## Documentation

Please visit our [website](https://heyapi.dev) for documentation, guides, migrating, and more.



## Sponsors

Partners behind the future of API tooling. [Become a sponsor](https://heyapi.dev/sponsors).

<h3 align="center">Gold</h3>

<table align="center">
  <tbody>
      <td align="center" width="50%">
        <p></p>
        <p>
          <a href="https://kutt.to/QM9Q2N" target="_blank">
            <picture height="50px">
              <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/opencode/logo-light.svg">
              <img alt="Opencode logo" height="50px" src="https://heyapi.dev/assets/opencode/logo-dark.svg">
            </picture>
          </a>
          <br/>
          The open source coding agent.
          <br/>
          <a href="https://kutt.to/QM9Q2N" style="text-decoration:none;" target="_blank">
            opencode.ai
          </a>
        </p>
        <p></p>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Silver</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/Dr9GuW" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/fastapi/logo-light.svg">
            <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/assets/fastapi/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/Dr9GuW" style="text-decoration:none;" target="_blank">
          fastapi.tiangolo.com
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/yZVkdV" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/brands/unblocked/logo-light.svg">
            <img alt="Unblocked logo" height="40px" src="https://heyapi.dev/assets/brands/unblocked/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/yZVkdV" style="text-decoration:none;" target="_blank">
          getunblocked.com
        </a>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Bronze</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/YpaKsX" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-dark-480w.webp">
            <img alt="Kinde logo" height="34px" src="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-480w.jpeg">
          </picture>
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/HW4GYR" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/photon/logo-light.svg">
            <img alt="Photon logo" height="34px" src="https://heyapi.dev/assets/photon/logo-dark.svg">
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>


## Migrating

You can learn more on the [Migrating](https://heyapi.dev/docs/openapi/typescript/migrating) page.



## License

Released under the [MIT License](https://github.com/hey-api/hey-api/blob/main/LICENSE).

---

### Overview (`packages/openapi-python/README.md`)

<div align="center">
  <img alt="Hey API presents openapi-python" height="214" src="https://heyapi.dev/assets/.gen/openapi-python-hero-640w.png" width="438">
  <h1><b>OpenAPI Python</b></h1>
  <p><em>“The ecosystem trusted by TypeScript developers is coming to Python codebases.”</em><br/><sub>— Lubos, Founder of Hey API</sub></p>
</div>

<p align="center">
  
  
  <a href="https://github.com/hey-api/hey-api/actions?query=branch%3Amain"><img src="https://github.com/hey-api/hey-api/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI status" /></a>
  <a href="https://github.com/hey-api/hey-api"><img src="https://img.shields.io/github/stars/hey-api/hey-api?style=flat&logo=github&label=GitHub&color=54C82D" alt="GitHub stars" /></a>
  <a href="https://github.com/hey-api/hey-api/blob/main/LICENSE"><img src="https://img.shields.io/github/license/hey-api/hey-api" alt="MIT License"></a>
</p>

<p align="center">
  
  <a href="https://heyapi.dev/docs/openapi/python/get-started">Manual</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://github.com/hey-api/hey-api/issues">Issues</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://heyapi.dev/docs/openapi/typescript/community/contributing">Contribute</a>
</p>

## About

The OpenAPI to Python code generator.

Generate production-grade SDKs and Pydantic models.

Part of the Hey API ecosystem.

## Features

- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugin for SDKs
- HTTP client for HTTPX
- highly customizable via plugins
- [sync with Hey API Registry](https://heyapi.dev/docs/openapi/typescript/integrations) for spec management




## Contributing

Want to see your code in products used by millions?

Start with our [Contributing](https://heyapi.dev/docs/openapi/typescript/community/contributing) guide and release your first feature.





## Sponsors

Partners behind the future of API tooling. [Become a sponsor](https://heyapi.dev/sponsors).

<h3 align="center">Gold</h3>

<table align="center">
  <tbody>
      <td align="center" width="50%">
        <p></p>
        <p>
          <a href="https://kutt.to/QM9Q2N" target="_blank">
            <picture height="50px">
              <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/opencode/logo-light.svg">
              <img alt="Opencode logo" height="50px" src="https://heyapi.dev/assets/opencode/logo-dark.svg">
            </picture>
          </a>
          <br/>
          The open source coding agent.
          <br/>
          <a href="https://kutt.to/QM9Q2N" style="text-decoration:none;" target="_blank">
            opencode.ai
          </a>
        </p>
        <p></p>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Silver</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/Dr9GuW" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/fastapi/logo-light.svg">
            <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/assets/fastapi/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/Dr9GuW" style="text-decoration:none;" target="_blank">
          fastapi.tiangolo.com
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/yZVkdV" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/brands/unblocked/logo-light.svg">
            <img alt="Unblocked logo" height="40px" src="https://heyapi.dev/assets/brands/unblocked/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/yZVkdV" style="text-decoration:none;" target="_blank">
          getunblocked.com
        </a>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Bronze</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/YpaKsX" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-dark-480w.webp">
            <img alt="Kinde logo" height="34px" src="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-480w.jpeg">
          </picture>
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/HW4GYR" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/photon/logo-light.svg">
            <img alt="Photon logo" height="34px" src="https://heyapi.dev/assets/photon/logo-dark.svg">
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>


## Quick Start

The fastest way to use `@hey-api/openapi-python` is via npx

```sh
npx @hey-api/openapi-python -i hey-api/backend -o src/client
```

Congratulations on creating your first client! 🎉 You can learn more about the generated files on the [Output](https://heyapi.dev/docs/openapi/python/output) page.

## Installation

You can download `@hey-api/openapi-python` from npm using your favorite package manager.

#### npm

```sh
npm install @hey-api/openapi-python -D -E
```

#### pnpm

```sh
pnpm add @hey-api/openapi-python -D -E
```

#### yarn

```sh
yarn add @hey-api/openapi-python -D -E
```

#### bun

```sh
bun add @hey-api/openapi-python -D
```

### Versioning

This package is in [initial development](https://semver.org/#spec-item-4). Please pin an exact version so you can safely upgrade when you're ready.

We publish [migration notes](https://heyapi.dev/docs/openapi/python/migrating) for every breaking release. You might not be impacted by a breaking change if you don't use the affected features.

## Usage

### CLI

Most people run `@hey-api/openapi-python` via CLI. To do that, add a script to your `package.json` file which will make `openapi-python` executable through script.

```json
"scripts": {
  "openapi-python": "openapi-python"
}
```

The above script can be executed by running `npm run openapi-python` or equivalent command in other package managers. Next, we will create a [configuration](https://heyapi.dev/docs/openapi/python/configuration) file and move our options from Quick Start to it.

### Node.js

You can also generate output programmatically by calling `createClient()` in a JavaScript/TypeScript file.

#### `script.ts`

```ts
import { createClient } from '@hey-api/openapi-python';

createClient({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
});
```



## Configuration

`@hey-api/openapi-python` supports loading configuration from any file inside your project root folder supported by [jiti loader](https://github.com/unjs/c12?tab=readme-ov-file#-features). Below are the most common file formats.

#### `openapi-python.config.ts`

```js
import { defineConfig } from '@hey-api/openapi-python';

export default defineConfig({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
});
```

#### `openapi-python.config.cjs`

```js
/** @type {import('@hey-api/openapi-python').UserConfig} */
module.exports = {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```

#### `openapi-python.config.mjs`

```js
/** @type {import('@hey-api/openapi-python').UserConfig} */
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```

Alternatively, you can use `openapi-python.config.js` and configure the export statement depending on your project setup.

### Input

You must set the input so we can load your OpenAPI specification. It can be a path or URL, object containing a path or URL, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.

> If you use an HTTPS URL with a self-signed certificate in development, you will need to set [`NODE_TLS_REJECT_UNAUTHORIZED=0`](https://github.com/hey-api/hey-api/issues/276#issuecomment-2043143501) in your environment.

### Output

You must set the output so we know where to generate your files. It can be a path to the destination folder or an object containing the destination folder path and optional settings.

> You should treat the output folder as a dependency. Do not directly modify its contents as your changes might be erased when you run `@hey-api/openapi-python` again.

## Parser

We parse your input before making it available to plugins. While configuring the parser is optional, it's the perfect place to modify or validate your input if needed.

## Plugins

Plugins are responsible for generating artifacts from your input. By default, Hey API will generate Pydantic models and SDK from your OpenAPI specification. You can add, remove, or customize any of the plugins. In fact, we highly encourage you to do so!

### Client

Clients are responsible for sending the actual HTTP requests. We default to HTTPX client if you're generating SDKs, but you can choose a different option from the available clients.

### Available Clients

- [`@hey-api/client-httpx`](https://heyapi.dev/docs/openapi/python/clients/httpx)

### Proposed Clients (Vote to Prioritize)

The following clients are roadmap proposals and are not started yet. You can help us prioritize them by voting on [GitHub](https://github.com/hey-api/hey-api/issues?q=state%3Aopen%20label%3A%22vote%20%F0%9F%93%A9%22).

- [`@hey-api/client-aiohttp`](https://heyapi.dev/docs/openapi/python/clients/aiohttp)
- [`@hey-api/client-requests`](https://heyapi.dev/docs/openapi/python/clients/requests)
- [`@hey-api/client-urllib3`](https://heyapi.dev/docs/openapi/python/clients/urllib3)

Don't see your client? [Build your own](https://heyapi.dev/docs/openapi/python/clients/custom) or let us know your interest by [opening an issue](https://github.com/hey-api/hey-api/issues).

### Available Plugins

These plugins help reduce boilerplate associated with third-party dependencies. Hey API natively supports the most popular packages. Please open an issue on [GitHub](https://github.com/hey-api/hey-api/issues) if you'd like us to support your favorite package.

- [`pydantic`](https://heyapi.dev/docs/openapi/python/plugins/pydantic)

### Proposed Plugins (Vote to Prioritize)

The following plugins are roadmap proposals and are not started yet. You can help us prioritize them by voting on [GitHub](https://github.com/hey-api/hey-api/issues?q=state%3Aopen%20label%3A%22vote%20%F0%9F%93%A9%22).

- [Attrs](https://heyapi.dev/docs/openapi/python/plugins/attrs)
- [Dataclasses](https://heyapi.dev/docs/openapi/python/plugins/dataclasses)
- [Factory Boy](https://heyapi.dev/docs/openapi/python/plugins/factory-boy)
- [Faker](https://heyapi.dev/docs/openapi/python/plugins/faker)
- [Marshmallow](https://heyapi.dev/docs/openapi/python/plugins/marshmallow)
- [Mimesis](https://heyapi.dev/docs/openapi/python/plugins/mimesis)

Don't see your plugin? [Build your own](https://heyapi.dev/docs/openapi/python/plugins/custom) or let us know your interest by [opening an issue](https://github.com/hey-api/hey-api/issues).

## Migrating

You can learn more on the [Migrating](https://heyapi.dev/docs/openapi/python/migrating) page.



## License

Released under the [MIT License](https://github.com/hey-api/hey-api/blob/main/LICENSE).

---

### Overview (`packages/openapi-ts/README.md`)

<div align="center">
  <img alt="Hey API presents openapi-ts" height="214" src="https://heyapi.dev/assets/.gen/openapi-ts-hero-640w.png" width="438">
  <h1><b>OpenAPI TypeScript</b></h1>
  <p><em>“OpenAPI codegen that just works.”</em><br/><sub>— Guillermo Rauch, CEO of Vercel</sub></p>
</div>

<p align="center">
  <a href="https://www.devtrends.dev/trends?c=v1.kZIBIg"><img src="https://api.devtrends.dev/badge/npm/%40hey-api%2Fopenapi-ts?period=month&style=flat&view=value" alt="DevTrends badge for @hey-api/openapi-ts" /></a>
  <a href="https://www.devtrends.dev/trends?c=v1.kZIBIg&v=change"><img src="https://api.devtrends.dev/badge/npm/%40hey-api%2Fopenapi-ts?period=year&style=flat&view=change" alt="DevTrends badge for @hey-api/openapi-ts" /></a>
  <a href="https://github.com/hey-api/hey-api/actions?query=branch%3Amain"><img src="https://github.com/hey-api/hey-api/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI status" /></a>
  <a href="https://github.com/hey-api/hey-api"><img src="https://img.shields.io/github/stars/hey-api/hey-api?style=flat&logo=github&label=GitHub&color=54C82D" alt="GitHub stars" /></a>
  <a href="https://github.com/hey-api/hey-api/blob/main/LICENSE"><img src="https://img.shields.io/github/license/hey-api/hey-api" alt="MIT License"></a>
</p>

<p align="center">
  <a href="https://stackblitz.com/edit/hey-api-example?file=openapi-ts.config.ts,src%2Fclient%2Fschemas.gen.ts,src%2Fclient%2Fsdk.gen.ts,src%2Fclient%2Ftypes.gen.ts">Demo</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://heyapi.dev/docs/openapi/typescript/get-started">Manual</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://github.com/hey-api/hey-api/issues">Issues</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://heyapi.dev/docs/openapi/typescript/community/contributing">Contribute</a>
</p>

## About

The OpenAPI to TypeScript code generator used by Vercel, OpenCode, and PayPal.

Generate production-grade SDKs, Zod schemas, TanStack Query hooks, or choose from 20+ other plugins.

Part of the Hey API ecosystem.

## Features

- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugins for SDKs, types, and schemas
- HTTP clients for Fetch API, Angular, Axios, Next.js, Nuxt, and more
- 20+ plugins to reduce third-party boilerplate
- highly customizable via plugins
- [sync with Hey API Registry](https://heyapi.dev/docs/openapi/typescript/integrations) for spec management



## Contributing

Want to see your code in products used by millions?

Start with our [Contributing](https://heyapi.dev/docs/openapi/typescript/community/contributing) guide and release your first feature.





## Sponsors

Partners behind the future of API tooling. [Become a sponsor](https://heyapi.dev/sponsors).

<h3 align="center">Gold</h3>

<table align="center">
  <tbody>
      <td align="center" width="50%">
        <p></p>
        <p>
          <a href="https://kutt.to/QM9Q2N" target="_blank">
            <picture height="50px">
              <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/opencode/logo-light.svg">
              <img alt="Opencode logo" height="50px" src="https://heyapi.dev/assets/opencode/logo-dark.svg">
            </picture>
          </a>
          <br/>
          The open source coding agent.
          <br/>
          <a href="https://kutt.to/QM9Q2N" style="text-decoration:none;" target="_blank">
            opencode.ai
          </a>
        </p>
        <p></p>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Silver</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/Dr9GuW" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/fastapi/logo-light.svg">
            <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/assets/fastapi/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/Dr9GuW" style="text-decoration:none;" target="_blank">
          fastapi.tiangolo.com
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/yZVkdV" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/brands/unblocked/logo-light.svg">
            <img alt="Unblocked logo" height="40px" src="https://heyapi.dev/assets/brands/unblocked/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/yZVkdV" style="text-decoration:none;" target="_blank">
          getunblocked.com
        </a>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Bronze</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/YpaKsX" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-dark-480w.webp">
            <img alt="Kinde logo" height="34px" src="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-480w.jpeg">
          </picture>
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/HW4GYR" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/photon/logo-light.svg">
            <img alt="Photon logo" height="34px" src="https://heyapi.dev/assets/photon/logo-dark.svg">
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>


## Quick Start

The fastest way to use `@hey-api/openapi-ts` is via npx

```sh
npx @hey-api/openapi-ts -i hey-api/backend -o src/client
```

Congratulations on creating your first client! 🎉 You can learn more about the generated files on the [Output](https://heyapi.dev/docs/openapi/typescript/output) page.

## Installation

You can download `@hey-api/openapi-ts` from npm using your favorite package manager.

#### npm

```sh
npm install @hey-api/openapi-ts -D -E
```

#### pnpm

```sh
pnpm add @hey-api/openapi-ts -D -E
```

#### yarn

```sh
yarn add @hey-api/openapi-ts -D -E
```

#### bun

```sh
bun add @hey-api/openapi-ts -D
```

### Versioning

This package is in [initial development](https://semver.org/#spec-item-4). Please pin an exact version so you can safely upgrade when you're ready.

We publish [migration notes](https://heyapi.dev/docs/openapi/typescript/migrating) for every breaking release. You might not be impacted by a breaking change if you don't use the affected features.

## Usage

### CLI

Most people run `@hey-api/openapi-ts` via CLI. To do that, add a script to your `package.json` file which will make `openapi-ts` executable through script.

```json
"scripts": {
  "openapi-ts": "openapi-ts"
}
```

The above script can be executed by running `npm run openapi-ts` or equivalent command in other package managers. Next, we will create a [configuration](https://heyapi.dev/docs/openapi/typescript/configuration) file and move our options from Quick Start to it.

### Node.js

You can also generate output programmatically by calling `createClient()` in a JavaScript/TypeScript file.

#### `script.ts`

```ts
import { createClient } from '@hey-api/openapi-ts';

createClient({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
});
```

### Vite

If you're using [Vite](https://vite.dev), you can integrate `@hey-api/openapi-ts` directly into your build pipeline with `@hey-api/vite-plugin`. Install it alongside the main package:

#### npm

```sh
npm install @hey-api/vite-plugin -D -E
```

#### pnpm

```sh
pnpm add @hey-api/vite-plugin -D -E
```

#### yarn

```sh
yarn add @hey-api/vite-plugin -D -E
```

#### bun

```sh
bun add @hey-api/vite-plugin -D
```

Then add the plugin to your Vite configuration:

#### `vite.config.ts`

```ts
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    heyApiPlugin({
      config: {
        input: 'hey-api/backend', // sign up at app.heyapi.dev
        output: 'src/client',
      },
    }),
  ],
});
```

See the [Vite](https://heyapi.dev/docs/openapi/typescript/configuration/vite) page for full configuration options.

## Configuration

`@hey-api/openapi-ts` supports loading configuration from any file inside your project root folder supported by [jiti loader](https://github.com/unjs/c12?tab=readme-ov-file#-features). Below are the most common file formats.

#### `openapi-ts.config.ts`

```js
import { defineConfig } from '@hey-api/openapi-ts';

export default defineConfig({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
});
```

#### `openapi-ts.config.cjs`

```js
/** @type {import('@hey-api/openapi-ts').UserConfig} */
module.exports = {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```

#### `openapi-ts.config.mjs`

```js
/** @type {import('@hey-api/openapi-ts').UserConfig} */
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```

Alternatively, you can use `openapi-ts.config.js` and configure the export statement depending on your project setup.

### Input

You must set the input so we can load your OpenAPI specification. It can be a path or URL, object containing a path or URL, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.

> If you use an HTTPS URL with a self-signed certificate in development, you will need to set [`NODE_TLS_REJECT_UNAUTHORIZED=0`](https://github.com/hey-api/hey-api/issues/276#issuecomment-2043143501) in your environment.

### Output

You must set the output so we know where to generate your files. It can be a path to the destination folder or an object containing the destination folder path and optional settings.

> You should treat the output folder as a dependency. Do not directly modify its contents as your changes might be erased when you run `@hey-api/openapi-ts` again.

## Parser

We parse your input before making it available to plugins. While configuring the parser is optional, it's the perfect place to modify or validate your input if needed.

## Plugins

Plugins are responsible for generating artifacts from your input. By default, Hey API will generate TypeScript interfaces and SDK from your OpenAPI specification. You can add, remove, or customize any of the plugins. In fact, we highly encourage you to do so!

### Client

Clients are responsible for sending the actual HTTP requests. We default to Fetch client if you're generating SDKs, but you can choose a different option from the available clients.

### Available Clients

- [`@hey-api/client-fetch`](https://heyapi.dev/docs/openapi/typescript/clients/fetch)
- [`@hey-api/client-angular`](https://heyapi.dev/docs/openapi/typescript/clients/angular)
- [`@hey-api/client-axios`](https://heyapi.dev/docs/openapi/typescript/clients/axios)
- [`@hey-api/client-ky`](https://heyapi.dev/docs/openapi/typescript/clients/ky)
- [`@hey-api/client-next`](https://heyapi.dev/docs/openapi/typescript/clients/next-js)
- [`@hey-api/client-nuxt`](https://heyapi.dev/docs/openapi/typescript/clients/nuxt)
- [`@hey-api/client-ofetch`](https://heyapi.dev/docs/openapi/typescript/clients/ofetch)

### Proposed Clients (Vote to Prioritize)

The following clients are roadmap proposals and are not started yet. You can help us prioritize them by voting on [GitHub](https://github.com/hey-api/hey-api/issues?q=state%3Aopen%20label%3A%22vote%20%F0%9F%93%A9%22).

- [`@hey-api/client-effect`](https://heyapi.dev/docs/openapi/typescript/clients/effect)

Don't see your client? [Build your own](https://heyapi.dev/docs/openapi/typescript/clients/custom) or let us know your interest by [opening an issue](https://github.com/hey-api/hey-api/issues).

### Available Plugins

These plugins help reduce boilerplate associated with third-party dependencies. Hey API natively supports the most popular packages. Please open an issue on [GitHub](https://github.com/hey-api/hey-api/issues) if you'd like us to support your favorite package.

- [`@angular/common`](https://heyapi.dev/docs/openapi/typescript/plugins/angular)
- [`@hey-api/schemas`](https://heyapi.dev/docs/openapi/typescript/plugins/schemas)
- [`@hey-api/sdk`](https://heyapi.dev/docs/openapi/typescript/plugins/sdk)
- [`@hey-api/transformers`](https://heyapi.dev/docs/openapi/typescript/plugins/transformers)
- [`@hey-api/typescript`](https://heyapi.dev/docs/openapi/typescript/plugins/typescript)
- [`@pinia/colada`](https://heyapi.dev/docs/openapi/typescript/plugins/pinia-colada)
- [`@tanstack/angular-query-experimental`](https://heyapi.dev/docs/openapi/typescript/plugins/tanstack-query)
- [`@tanstack/preact-query`](https://heyapi.dev/docs/openapi/typescript/plugins/tanstack-query)
- [`@tanstack/react-query`](https://heyapi.dev/docs/openapi/typescript/plugins/tanstack-query)
- [`@tanstack/solid-query`](https://heyapi.dev/docs/openapi/typescript/plugins/tanstack-query)
- [`@tanstack/svelte-query`](https://heyapi.dev/docs/openapi/typescript/plugins/tanstack-query)
- [`@tanstack/vue-query`](https://heyapi.dev/docs/openapi/typescript/plugins/tanstack-query)
- [`fastify`](https://heyapi.dev/docs/openapi/typescript/plugins/fastify)
- [`orpc`](https://heyapi.dev/docs/openapi/typescript/plugins/orpc)
- [`nestjs`](https://heyapi.dev/docs/openapi/typescript/plugins/nest)
- [`valibot`](https://heyapi.dev/docs/openapi/typescript/plugins/valibot)
- [`zod`](https://heyapi.dev/docs/openapi/typescript/plugins/zod)

### Proposed Plugins (Vote to Prioritize)

The following plugins are roadmap proposals and are not started yet. You can help us prioritize them by voting on [GitHub](https://github.com/hey-api/hey-api/issues?q=state%3Aopen%20label%3A%22vote%20%F0%9F%93%A9%22).

- [Adonis](https://heyapi.dev/docs/openapi/typescript/plugins/adonis)
- [Ajv](https://heyapi.dev/docs/openapi/typescript/plugins/ajv)
- [Arktype](https://heyapi.dev/docs/openapi/typescript/plugins/arktype)
- [Chance](https://heyapi.dev/docs/openapi/typescript/plugins/chance)
- [Elysia](https://heyapi.dev/docs/openapi/typescript/plugins/elysia)
- [Express](https://heyapi.dev/docs/openapi/typescript/plugins/express)
- [Faker](https://heyapi.dev/docs/openapi/typescript/plugins/faker)
- [Falso](https://heyapi.dev/docs/openapi/typescript/plugins/falso)
- [Hono](https://heyapi.dev/docs/openapi/typescript/plugins/hono)
- [Joi](https://heyapi.dev/docs/openapi/typescript/plugins/joi)
- [Koa](https://heyapi.dev/docs/openapi/typescript/plugins/koa)
- [MSW](https://heyapi.dev/docs/openapi/typescript/plugins/msw)
- [Nock](https://heyapi.dev/docs/openapi/typescript/plugins/nock)
- [Superstruct](https://heyapi.dev/docs/openapi/typescript/plugins/superstruct)
- [Supertest](https://heyapi.dev/docs/openapi/typescript/plugins/supertest)
- [SWR](https://heyapi.dev/docs/openapi/typescript/plugins/swr)
- [TanStack Start](https://heyapi.dev/docs/openapi/typescript/plugins/tanstack-start)
- [TypeBox](https://heyapi.dev/docs/openapi/typescript/plugins/typebox)
- [Yup](https://heyapi.dev/docs/openapi/typescript/plugins/yup)
- [Zustand](https://heyapi.dev/docs/openapi/typescript/plugins/zustand)

Don't see your plugin? [Build your own](https://heyapi.dev/docs/openapi/typescript/plugins/custom) or let us know your interest by [opening an issue](https://github.com/hey-api/hey-api/issues).

## Migrating

You can learn more on the [Migrating](https://heyapi.dev/docs/openapi/typescript/migrating) page.



## License

Released under the [MIT License](https://github.com/hey-api/hey-api/blob/main/LICENSE).

---

### Overview (`packages/spec-types/README.md`)

<div align="center">
  <img alt="Hey API presents openapi-ts" height="214" src="https://heyapi.dev/assets/.gen/openapi-ts-hero-640w.png" width="438">
  <h1><b>Spec Types</b></h1>
  <p>TypeScript definitions for OpenAPI and JSON Schema specifications with complete inline documentation.</p>
</div>

<p align="center">
  <a href="https://www.devtrends.dev/trends?c=v1.kZIBzQM2"><img src="https://api.devtrends.dev/badge/npm/%40hey-api%2Fspec-types?period=month&style=flat&view=value" alt="DevTrends badge for @hey-api/spec-types" /></a>
  <a href="https://www.devtrends.dev/trends?c=v1.kZIBzQM2&v=change"><img src="https://api.devtrends.dev/badge/npm/%40hey-api%2Fspec-types?period=year&style=flat&view=change" alt="DevTrends badge for @hey-api/spec-types" /></a>
  <a href="https://github.com/hey-api/hey-api/actions?query=branch%3Amain"><img src="https://github.com/hey-api/hey-api/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI status" /></a>
  <a href="https://github.com/hey-api/hey-api"><img src="https://img.shields.io/github/stars/hey-api/hey-api?style=flat&logo=github&label=GitHub&color=54C82D" alt="GitHub stars" /></a>
  <a href="https://github.com/hey-api/hey-api/blob/main/LICENSE"><img src="https://img.shields.io/github/license/hey-api/hey-api" alt="MIT License"></a>
</p>

<p align="center">
  <a href="https://heyapi.dev">Manual</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://github.com/hey-api/hey-api/issues">Issues</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://heyapi.dev/docs/openapi/typescript/community/contributing">Contribute</a>
</p>

## About

TypeScript definitions for OpenAPI and JSON Schema specifications with complete inline documentation.

Part of the Hey API ecosystem.

## Features

- OpenAPI 2.0 (Swagger), 3.0, and 3.1 specifications
- JSON Schema Draft 4 and Draft 2020-12
- inline JSDoc on every property
- zero runtime footprint, types only



## Contributing

Want to see your code in products used by millions?

Start with our [Contributing](https://heyapi.dev/docs/openapi/typescript/community/contributing) guide and release your first feature.





## Sponsors

Partners behind the future of API tooling. [Become a sponsor](https://heyapi.dev/sponsors).

<h3 align="center">Gold</h3>

<table align="center">
  <tbody>
      <td align="center" width="50%">
        <p></p>
        <p>
          <a href="https://kutt.to/QM9Q2N" target="_blank">
            <picture height="50px">
              <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/opencode/logo-light.svg">
              <img alt="Opencode logo" height="50px" src="https://heyapi.dev/assets/opencode/logo-dark.svg">
            </picture>
          </a>
          <br/>
          The open source coding agent.
          <br/>
          <a href="https://kutt.to/QM9Q2N" style="text-decoration:none;" target="_blank">
            opencode.ai
          </a>
        </p>
        <p></p>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Silver</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/Dr9GuW" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/fastapi/logo-light.svg">
            <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/assets/fastapi/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/Dr9GuW" style="text-decoration:none;" target="_blank">
          fastapi.tiangolo.com
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/yZVkdV" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/brands/unblocked/logo-light.svg">
            <img alt="Unblocked logo" height="40px" src="https://heyapi.dev/assets/brands/unblocked/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/yZVkdV" style="text-decoration:none;" target="_blank">
          getunblocked.com
        </a>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Bronze</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/YpaKsX" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-dark-480w.webp">
            <img alt="Kinde logo" height="34px" src="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-480w.jpeg">
          </picture>
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/HW4GYR" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/photon/logo-light.svg">
            <img alt="Photon logo" height="34px" src="https://heyapi.dev/assets/photon/logo-dark.svg">
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>


## Installation

You can download `@hey-api/spec-types` from npm using your favorite package manager.

#### npm

```sh
npm install @hey-api/spec-types -D -E
```

#### pnpm

```sh
pnpm add @hey-api/spec-types -D -E
```

#### yarn

```sh
yarn add @hey-api/spec-types -D -E
```

#### bun

```sh
bun add @hey-api/spec-types -D
```

## Usage

### OpenAPI

Hover over any property to see its definition from the specification.

```ts
import type { OpenAPIV3_1 } from '@hey-api/spec-types';

const doc = {
  openapi: '3.1.2',
  info: {
    title: 'My OpenAPI document',
    version: '1.0.0',
  },
} satisfies OpenAPIV3_1.Document;
```

### JSON Schema

Full type coverage for Draft 4 and Draft 2020-12 schemas.

```ts
import type { JSONSchemaDraft2020_12 } from '@hey-api/spec-types';

const doc = {
  properties: {
    foo: {
      type: 'string',
    },
  },
  type: 'object',
} satisfies JSONSchemaDraft2020_12.Document;
```



## License

Released under the [MIT License](https://github.com/hey-api/hey-api/blob/main/LICENSE).

---

### Overview (`packages/vite-plugin/README.md`)

<div align="center">
  <img alt="Hey API presents openapi-ts" height="214" src="https://heyapi.dev/assets/.gen/openapi-ts-hero-640w.png" width="438">
  <h1><b>Vite Plugin</b></h1>
  <p>Vite plugin for <code>@hey-api/openapi-ts</code>.</p>
</div>

<p align="center">
  <a href="https://www.devtrends.dev/trends?c=v1.kZIAzQaO"><img src="https://api.devtrends.dev/badge/npm/%40hey-api%2Fvite-plugin?period=month&style=flat&view=value" alt="DevTrends badge for @hey-api/vite-plugin" /></a>
  <a href="https://www.devtrends.dev/trends?c=v1.kZIAzQaO&v=change"><img src="https://api.devtrends.dev/badge/npm/%40hey-api%2Fvite-plugin?period=year&style=flat&view=change" alt="DevTrends badge for @hey-api/vite-plugin" /></a>
  <a href="https://github.com/hey-api/hey-api/actions?query=branch%3Amain"><img src="https://github.com/hey-api/hey-api/actions/workflows/ci.yml/badge.svg?event=push&branch=main" alt="CI status" /></a>
  <a href="https://github.com/hey-api/hey-api"><img src="https://img.shields.io/github/stars/hey-api/hey-api?style=flat&logo=github&label=GitHub&color=54C82D" alt="GitHub stars" /></a>
  <a href="https://github.com/hey-api/hey-api/blob/main/LICENSE"><img src="https://img.shields.io/github/license/hey-api/hey-api" alt="MIT License"></a>
</p>

<p align="center">
  <a href="https://heyapi.dev">Manual</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://github.com/hey-api/hey-api/issues">Issues</a>
  <span>&nbsp;•&nbsp;</span>
  <a href="https://heyapi.dev/docs/openapi/typescript/community/contributing">Contribute</a>
</p>

## About

[Vite](https://vite.dev) is a blazing fast frontend build tool powering the next generation of web applications.

The Vite plugin integrates [`@hey-api/openapi-ts`](https://heyapi.dev/docs/openapi/typescript) into the Vite build pipeline, running automatically whenever Vite resolves its configuration – no separate script or manual step required.

Part of the Hey API ecosystem.

## Features

- runs automatically as part of your Vite build
- reads your existing configuration (or accepts inline config)
- supports Vite 5, 6, 7, and 8
- [sync with Hey API Registry](https://heyapi.dev/docs/openapi/typescript/integrations) for spec management



## Contributing

Want to see your code in products used by millions?

Start with our [Contributing](https://heyapi.dev/docs/openapi/typescript/community/contributing) guide and release your first feature.





## Sponsors

Partners behind the future of API tooling. [Become a sponsor](https://heyapi.dev/sponsors).

<h3 align="center">Gold</h3>

<table align="center">
  <tbody>
      <td align="center" width="50%">
        <p></p>
        <p>
          <a href="https://kutt.to/QM9Q2N" target="_blank">
            <picture height="50px">
              <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/opencode/logo-light.svg">
              <img alt="Opencode logo" height="50px" src="https://heyapi.dev/assets/opencode/logo-dark.svg">
            </picture>
          </a>
          <br/>
          The open source coding agent.
          <br/>
          <a href="https://kutt.to/QM9Q2N" style="text-decoration:none;" target="_blank">
            opencode.ai
          </a>
        </p>
        <p></p>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Silver</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/Dr9GuW" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/fastapi/logo-light.svg">
            <img alt="FastAPI logo" height="40px" src="https://heyapi.dev/assets/fastapi/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/Dr9GuW" style="text-decoration:none;" target="_blank">
          fastapi.tiangolo.com
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/yZVkdV" target="_blank">
          <picture height="40px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/brands/unblocked/logo-light.svg">
            <img alt="Unblocked logo" height="40px" src="https://heyapi.dev/assets/brands/unblocked/logo-dark.svg">
          </picture>
        </a>
        <br/>
        <a href="https://kutt.to/yZVkdV" style="text-decoration:none;" target="_blank">
          getunblocked.com
        </a>
      </td>
    </tr>
  </tbody>
</table>

<h3 align="center">Bronze</h3>

<table align="center">
  <tbody>
    <tr>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/YpaKsX" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-dark-480w.webp">
            <img alt="Kinde logo" height="34px" src="https://heyapi.dev/assets/.gen/kinde-logo-wordmark-480w.jpeg">
          </picture>
        </a>
      </td>
      <td align="center" width="33.333%">
        <a href="https://kutt.to/HW4GYR" target="_blank">
          <picture height="34px">
            <source media="(prefers-color-scheme: dark)" srcset="https://heyapi.dev/assets/photon/logo-light.svg">
            <img alt="Photon logo" height="34px" src="https://heyapi.dev/assets/photon/logo-dark.svg">
          </picture>
        </a>
      </td>
    </tr>
  </tbody>
</table>


## Installation

You can download `@hey-api/vite-plugin` from npm using your favorite package manager.

#### npm

```sh
npm install @hey-api/vite-plugin -D -E
```

#### pnpm

```sh
pnpm add @hey-api/vite-plugin -D -E
```

#### yarn

```sh
yarn add @hey-api/vite-plugin -D -E
```

#### bun

```sh
bun add @hey-api/vite-plugin -D
```

## Usage

Add the plugin to your `vite.config.ts`:

```ts
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [heyApiPlugin()],
});
```

The plugin will automatically pick up your [configuration](https://heyapi.dev/docs/openapi/typescript/configuration) file. You can also pass options inline using the `config` option:

```ts
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    heyApiPlugin({
      config: {
        input: 'hey-api/backend', // sign up at app.heyapi.dev
        output: 'src/client',
      },
    }),
  ],
});
```



## License

Released under the [MIT License](https://github.com/hey-api/hey-api/blob/main/LICENSE).

---

### Overview (`packages/openapi-python/pypi/README.md`)

# Hey API

OpenAPI to Python code generator. Production-grade SDKs and Pydantic models. Built by [Hey API](https://heyapi.dev).

## Installation

### uv

Install:

```sh
uv add hey-api
```

Or run without installing:

```sh
uvx hey-api --help
```

### pip

Install:

```sh
pip install hey-api
```

Or run without installing:

```sh
pipx run hey-api
```

## Usage

```sh
hey-api --help
```

## Resources

- [Manual](https://heyapi.dev/docs/openapi/python/get-started)
- [GitHub](https://github.com/hey-api/hey-api)
- [npm](https://npmjs.com/package/@hey-api/openapi-python)
- [Sponsor](https://heyapi.dev/sponsors)

---

### Web Src Content Docs Index (`web/src/content/docs/index.mdx`)

---
title: OpenAPI to code in seconds.
description: Generate production-grade API infrastructure from your OpenAPI spec. SDKs, validators, query hooks, and 20+ plugins across TypeScript and Python. Free and open source.
template: splash
---

import Page from '@/components/pages/codegen/page.astro';

<Page />

---

### Web Src Content Docs Sponsors (`web/src/content/docs/sponsors.mdx`)

---
title: Sponsors
description: Fuel the future of API tooling.
template: splash
---

import SponsorsPage from '@/components/pages/sponsors/page.astro';

<SponsorsPage />

---

### Web Src Content Docs Codegen Openapi Python (`web/src/content/docs/codegen/openapi/python.mdx`)

---
title: OpenAPI to Python in seconds.
description: Generate production-grade API infrastructure from your OpenAPI spec. Typed SDKs and Pydantic models. Free and open source.
template: splash
---

import Page from '@/components/pages/codegen/page.astro';

<Page defaultOutput="python" />

---

### Web Src Content Docs Codegen Openapi Typescript (`web/src/content/docs/codegen/openapi/typescript.mdx`)

---
title: OpenAPI to TypeScript in seconds.
description: Generate production-grade API infrastructure from your OpenAPI spec. Typed SDKs, Zod schemas, TanStack Query hooks, and 20+ plugins. Free and open source.
template: splash
---

import Page from '@/components/pages/codegen/page.astro';

<Page defaultOutput="typescript" />

---

### Web Src Content Docs Docs Openapi Python Configuration (`web/src/content/docs/docs/openapi/python/configuration.mdx`)

---
title: Configuration
description: Configure @hey-api/openapi-python.
sidebar:
  label: Overview
---

import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import InputTabs from '@/components/code-groups/InputTabs.mdx';
import OutputTabs from '@/components/code-groups/OutputTabs.mdx';
import UserConfig from '@/components/UserConfig.astro';

# Configuration

`@hey-api/openapi-python` supports loading configuration from any file inside your project root folder supported by [jiti loader](https://github.com/unjs/c12?tab=readme-ov-file#-features). Below are the most common file formats.

<Tabs>
  <TabItem label="openapi-python.config.ts">
```ts
import { defineConfig } from '@hey-api/openapi-python';

export default defineConfig({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
});
```
  </TabItem>
  <TabItem label="openapi-python.config.cjs">
```js
/** @type {import('@hey-api/openapi-python').UserConfig} */
module.exports = {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
  <TabItem label="openapi-python.config.mjs">
```js
/** @type {import('@hey-api/openapi-python').UserConfig} */
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
</Tabs>

Alternatively, you can use `openapi-python.config.js` and configure the export statement depending on your project setup.

## Input

You must provide an input so we can load your OpenAPI specification.

The input can be a string path, URL, [API registry](/docs/openapi/python/configuration/input#api-registry) shorthand, an object containing any of these, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.

You can learn more on the [Input](/docs/openapi/python/configuration/input) page.

<InputTabs />

:::tip
If you use an HTTPS URL with a self-signed certificate in development, you will need to set [`NODE_TLS_REJECT_UNAUTHORIZED=0`](https://github.com/hey-api/hey-api/issues/276#issuecomment-2043143501) in your environment.
:::

## Output

You must set the output so we know where to generate your files. It can be a path to the destination folder or an object containing the destination folder path and optional settings.

You can learn more on the [Output](/docs/openapi/python/configuration/output) page.

<OutputTabs />

:::tip
You should treat the output folder as a dependency. Do not directly modify its contents as your changes might be erased when you run `@hey-api/openapi-python` again.
:::

## Parser

We parse your input before making it available to plugins. Configuring the parser is optional, but it provides an ideal opportunity to modify or validate your input as needed.

You can learn more on the [Parser](/docs/openapi/python/configuration/parser) page.

## Plugins

Plugins are responsible for generating artifacts from your input. By default, Hey API will generate Pydantic models and SDK from your OpenAPI specification. You can add, remove, or customize any of the plugins. In fact, we highly encourage you to do so!

You can learn more on the [Output](/docs/openapi/python/output) page.

## Advanced

More complex configuration scenarios can be handled by providing an array of inputs, outputs, or configurations.

### Multiple jobs

Throughout this documentation, we generally reference single job configurations. However, you can easily run multiple jobs by providing an array of configuration objects.

<Tabs>
  <TabItem label="config">
```js
export default [
  {
    input: 'foo.yaml',
    output: 'src/foo',
  },
  {
    input: 'bar.yaml',
    output: 'src/bar',
  },
];
```
  </TabItem>
  <TabItem label="example">
<FileTree>
- src
  - foo
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
  - bar
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
</FileTree>
  </TabItem>
</Tabs>

### Job matrix

Reusing configuration across multiple jobs is possible by defining a job matrix. You can create a job matrix by providing `input` and `output` arrays of matching length.

<Tabs>
  <TabItem label="config">
```js
export default {
  input: ['foo.yaml', 'bar.yaml'],
  output: ['src/foo', 'src/bar'],
};
```
  </TabItem>
  <TabItem label="example">
<FileTree>
- src
  - foo
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
  - bar
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
</FileTree>
  </TabItem>
</Tabs>

### Merging inputs

You can merge inputs by defining multiple inputs and a single output.

<Tabs>
  <TabItem label="config">
```js
export default {
  input: ['foo.yaml', 'bar.yaml'],
  output: 'src/client',
};
```
  </TabItem>
  <TabItem label="example">
<FileTree>
- src
  - client
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
</FileTree>
  </TabItem>
</Tabs>

<UserConfig folder="config" package="openapi-python" />
{/* <Examples /> */}

---

### Web Src Content Docs Docs Openapi Python Get Started (`web/src/content/docs/docs/openapi/python/get-started.mdx`)

---
title: Get Started
description: Get started with @hey-api/openapi-python.
---

import InstallCommand from '@/components/package-managers/InstallCommand.astro';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';

# Get Started

[@hey-api/openapi-python](https://github.com/hey-api/hey-api) generates Python code from OpenAPI specifications. Point it at your spec, pick your plugins, and get production-grade code in seconds.

{/* Used by companies like Vercel, OpenCode, and PayPal. */}

> _“The ecosystem trusted by TypeScript developers is coming to Python codebases.”_
>
> <sub>— Lubos, Founder of Hey API</sub>

{/* ### Demo

<StackBlitz
  example="hey-api-example"
  openFile={[
    'openapi-ts.config.ts',
    'src/client/schemas.gen.ts',
    'src/client/sdk.gen.ts',
    'src/client/types.gen.ts',
  ]}
/> */}

## Features

- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugin for SDKs
- HTTP client for HTTPX
- highly customizable via plugins
- [sync with Hey API Registry](/docs/openapi/typescript/integrations) for spec management
{/* - 20+ plugins to reduce third-party boilerplate */}

## Quick Start

The fastest way to use `@hey-api/openapi-python` is via npx

```sh
npx @hey-api/openapi-python -i hey-api/backend -o src/client
```

Congratulations on creating your first client! 🎉 You can learn more about the generated files on the [Output](/docs/openapi/python/output) page.

## Installation

You can download `@hey-api/openapi-python` from npm using your favorite package manager.

<InstallCommand packageName="@hey-api/openapi-python" />

### Versioning

This package is in [initial development](https://semver.org/#spec-item-4). Please pin an exact version so you can safely upgrade when you're ready.

We publish [migration notes](/docs/openapi/python/migrating) for every breaking release. You might not be impacted by a breaking change if you don't use the affected features.

## Usage

### CLI

Most people run `@hey-api/openapi-python` via CLI. To do that, add a script to your `package.json` file which will make `openapi-python` executable through script.

```json title="package.json"
"scripts": {
  "openapi-python": "openapi-python"
}
```

The above script can be executed by running `npm run openapi-python` or equivalent command in other package managers. Next, we will create a [configuration](/docs/openapi/python/configuration) file and move our options from Quick Start to it.

### Node.js

You can also generate output programmatically by calling `createClient()` in a JavaScript/TypeScript file.

```ts title="script.ts"
import { createClient } from '@hey-api/openapi-python';

createClient({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
});
```

{/* ### Vite

If you're using [Vite](https://vite.dev) 5, 6, 7, or 8, you can integrate `@hey-api/openapi-python` directly into your build pipeline with `@hey-api/vite-plugin`. Install it alongside the main package:

<InstallCommand packageName="@hey-api/vite-plugin" />

Then add the plugin to your Vite configuration:

```ts title="vite.config.ts"
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    heyApiPlugin({
      config: {
        input: 'hey-api/backend', // sign up at app.heyapi.dev
        output: 'src/client',
      },
    }),
  ],
});
```

See the [Vite](/docs/openapi/typescript/configuration/vite) page for full configuration options. */}

### Configuration

It's a good practice to extract your configuration into a separate file. Learn how to do that and discover available options on the [Configuration](/docs/openapi/python/configuration) page.

{/* <Examples /> */}

---

### Web Src Content Docs Docs Openapi Python Migrating (`web/src/content/docs/docs/openapi/python/migrating.mdx`)

---
title: Migrating
description: Migrating to @hey-api/openapi-python.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';

# Migrating

Hey API is in active development, which allows us to move quickly and continuously improve the project. That pace sometimes comes with breaking changes. This page documents those changes and provides migration guidance for each release. If you need help with a migration, please [open an issue](https://github.com/hey-api/hey-api/issues).

## v0.1.0

Coming soon.

---

### Web Src Content Docs Docs Openapi Python Output (`web/src/content/docs/docs/openapi/python/output.mdx`)

---
title: Output
description: Learn about files generated with @hey-api/openapi-python.
---

import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

# Output

Every generated file in your output folder is created by a plugin. This page describes the default output, but similar logic applies to all plugins.

## Overview

If you use the default configuration, your [project](https://stackblitz.com/edit/hey-api-example?file=openapi-ts.config.ts,src%2Fclient%2Fschemas.gen.ts,src%2Fclient%2Fsdk.gen.ts,src%2Fclient%2Ftypes.gen.ts) might look like this.

<FileTree>
- my-app/
  - node_modules/
  - src/
    - client/
      - client/
      - core/
      - client.gen.ts
      - index.ts
      - sdk.gen.ts
      - types.gen.ts
    - index.ts
  - package.json
</FileTree>

Your actual output depends on your Hey API configuration. It may contain a different number of files and their contents might differ.

Let's go through each file in the `src/client` folder and explain what it looks like, what it does, and how to use it.

## Client

`client.gen.ts` is generated by [client plugins](/docs/openapi/typescript/clients). If you choose to generate SDKs (enabled by default), we use the Fetch client unless specified otherwise.

```ts title="client.gen.ts"
import { createClient, createConfig } from './client';

export const client = createClient(createConfig());
```

The contents of this file are consumed by SDKs, but you can also import `client` in your application to perform additional configuration or send manual requests.

### Bundle

Client plugins provide their bundles inside `client` and `core` folders. The contents of these folders don't depend on the provided input. Everything inside these folders serves as a scaffolding so the generated code can make HTTP requests.

## TypeScript

You can learn more on the [TypeScript](/docs/openapi/typescript/plugins/typescript) page.

## SDK

You can learn more on the [SDK](/docs/openapi/typescript/plugins/sdk) page.

## Entry File

`index.ts` is not generated by any specific plugin. It's meant for convenience and by default, it re-exports every artifact generated by default plugins (TypeScript and SDK).

```ts title="index.ts"
export * from './sdk.gen';
export * from './types.gen';
```

### Disable entry file

We recommend importing artifacts from their respective files to avoid ambiguity, but we leave this choice up to you.

```ts title="index.ts"
import type { Pet } from './client';
// or
import type { Pet } from './client/types.gen';
```

If you're not importing artifacts from the entry file, you can skip generating it altogether by setting the `output.entryFile` option to `false`.

```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    entryFile: false,
    path: 'src/client',
  },
};
```

### Re-export artifacts

You can choose which artifacts should be re-exported from the entry file using the `includeInEntry` option on any plugin. For example, we can re-export all [Zod](/docs/openapi/typescript/plugins/zod) plugin artifacts by setting `includeInEntry` to `true`:

<Tabs>
  <TabItem label="example">
```ts title="index.ts"
export {
  zAddPetData,
  zAddPetResponse,
  zApiResponse,
  zCategory,
  // ...more exports
} from './zod.gen';
```
  </TabItem>
  <TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      includeInEntry: true,
      name: 'zod',
    },
  ],
};
```
  </TabItem>
</Tabs>

Or we can re-export only specific artifacts by providing a predicate function:

<Tabs>
  <TabItem label="example">
```ts title="index.ts"
export { zTag } from './zod.gen';
```
  </TabItem>
  <TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      includeInEntry: (symbol) => symbol.name === 'zTag',
      name: 'zod',
    },
  ],
};
```
  </TabItem>
</Tabs>

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Clients (`web/src/content/docs/docs/openapi/typescript/clients.mdx`)

---
title: Clients
description: HTTP clients for Hey API. Compatible with all our features.
sidebar:
  label: Overview
---

import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

# HTTP Clients

We all send HTTP requests in a slightly different way. Hey API doesn't force you to use any specific technology. What we do, however, is support your choice with great clients. All seamlessly integrated with our other features.

## Features

- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Plugins

Hey API natively supports the following clients.

- [Fetch API](/docs/openapi/typescript/clients/fetch)
- [Angular](/docs/openapi/typescript/clients/angular)
- [Axios](/docs/openapi/typescript/clients/axios)
- [Ky](/docs/openapi/typescript/clients/ky)
- [Next.js](/docs/openapi/typescript/clients/next-js)
- [Nuxt](/docs/openapi/typescript/clients/nuxt)
- [OFetch](/docs/openapi/typescript/clients/ofetch)
- [Effect](/docs/openapi/typescript/clients/effect) <Badge text="Vote" variant="tip" />
- [Got](/docs/openapi/typescript/clients/got) <Badge text="Vote" variant="tip" />

Don't see your client? [Build your own](/docs/openapi/typescript/clients/custom) or let us know your interest by [opening an issue](https://github.com/hey-api/hey-api/issues).

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Configuration (`web/src/content/docs/docs/openapi/typescript/configuration.mdx`)

---
title: Configuration
description: Configure @hey-api/openapi-ts.
sidebar:
  label: Overview
---

import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import InputTabs from '@/components/code-groups/InputTabs.mdx';
import OutputTabs from '@/components/code-groups/OutputTabs.mdx';
import UserConfig from '@/components/UserConfig.astro';

# Configuration

`@hey-api/openapi-ts` supports loading configuration from any file inside your project root folder supported by [jiti loader](https://github.com/unjs/c12?tab=readme-ov-file#-features). Below are the most common file formats.

<Tabs>
  <TabItem label="openapi-ts.config.ts">
```ts
import { defineConfig } from '@hey-api/openapi-ts';

export default defineConfig({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
});
```
  </TabItem>
  <TabItem label="openapi-ts.config.cjs">
```js
/** @type {import('@hey-api/openapi-ts').UserConfig} */
module.exports = {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
  <TabItem label="openapi-ts.config.mjs">
```js
/** @type {import('@hey-api/openapi-ts').UserConfig} */
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
</Tabs>

Alternatively, you can use `openapi-ts.config.js` and configure the export statement depending on your project setup.

## Input

You must provide an input so we can load your OpenAPI specification.

The input can be a string path, URL, [API registry](/docs/openapi/typescript/configuration/input#api-registry) shorthand, an object containing any of these, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.

You can learn more on the [Input](/docs/openapi/typescript/configuration/input) page.

<InputTabs />

:::tip
If you use an HTTPS URL with a self-signed certificate in development, you will need to set [`NODE_TLS_REJECT_UNAUTHORIZED=0`](https://github.com/hey-api/hey-api/issues/276#issuecomment-2043143501) in your environment.
:::

## Output

You must set the output so we know where to generate your files. It can be a path to the destination folder or an object containing the destination folder path and optional settings.

You can learn more on the [Output](/docs/openapi/typescript/configuration/output) page.

<OutputTabs />

:::tip
You should treat the output folder as a dependency. Do not directly modify its contents as your changes might be erased when you run `@hey-api/openapi-ts` again.
:::

## Parser

We parse your input before making it available to plugins. Configuring the parser is optional, but it provides an ideal opportunity to modify or validate your input as needed.

You can learn more on the [Parser](/docs/openapi/typescript/configuration/parser) page.

## Plugins

Plugins are responsible for generating artifacts from your input. By default, Hey API will generate TypeScript interfaces and SDK from your OpenAPI specification. You can add, remove, or customize any of the plugins. In fact, we highly encourage you to do so!

You can learn more on the [Output](/docs/openapi/typescript/output) page.

## Advanced

More complex configuration scenarios can be handled by providing an array of inputs, outputs, or configurations.

### Multiple jobs

Throughout this documentation, we generally reference single job configurations. However, you can easily run multiple jobs by providing an array of configuration objects.

<Tabs>
  <TabItem label="config">
```js
export default [
  {
    input: 'foo.yaml',
    output: 'src/foo',
  },
  {
    input: 'bar.yaml',
    output: 'src/bar',
  },
];
```
  </TabItem>
  <TabItem label="example">
<FileTree>
- src
  - foo
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
  - bar
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
</FileTree>
  </TabItem>
</Tabs>

### Job matrix

Reusing configuration across multiple jobs is possible by defining a job matrix. You can create a job matrix by providing `input` and `output` arrays of matching length.

<Tabs>
  <TabItem label="config">
```js
export default {
  input: ['foo.yaml', 'bar.yaml'],
  output: ['src/foo', 'src/bar'],
};
```
  </TabItem>
  <TabItem label="example">
<FileTree>
- src
  - foo
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
  - bar
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
</FileTree>
  </TabItem>
</Tabs>

### Merging inputs

You can merge inputs by defining multiple inputs and a single output.

<Tabs>
  <TabItem label="config">
```js
export default {
  input: ['foo.yaml', 'bar.yaml'],
  output: 'src/client',
};
```
  </TabItem>
  <TabItem label="example">
<FileTree>
- src
  - client
    - client/
    - core/
    - client.gen.ts
    - index.ts
    - sdk.gen.ts
    - types.gen.ts
</FileTree>
  </TabItem>
</Tabs>

<UserConfig folder="config" package="openapi-ts" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Core (`web/src/content/docs/docs/openapi/typescript/core.mdx`)

---
title: Core Plugins
description: Learn about the core plugins provided by Hey API.
sidebar:
  label: Overview
---

import Examples from '@/components/Examples.astro';

# Core

Apart from being responsible for the default output, core plugins are the foundation for other plugins. Instead of creating their own primitives, other plugins can reuse the artifacts from core plugins. This results in a smaller output size and a better user experience.

## Plugins

Hey API provides the following core plugins.

- [TypeScript](/docs/openapi/typescript/plugins/typescript)
- [SDK](/docs/openapi/typescript/plugins/sdk)
- [Transformers](/docs/openapi/typescript/plugins/transformers)
- [Schemas](/docs/openapi/typescript/plugins/schemas)

Need another core plugin? Let us know by [opening an issue](https://github.com/hey-api/hey-api/issues).

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Get Started (`web/src/content/docs/docs/openapi/typescript/get-started.mdx`)

---
title: Get Started
description: Get started with @hey-api/openapi-ts.
---

import InstallCommand from '@/components/package-managers/InstallCommand.astro';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';

# Get Started

[@hey-api/openapi-ts](https://github.com/hey-api/hey-api) generates TypeScript code from OpenAPI specifications. Point it at your spec, pick your plugins, and get production-grade code in seconds.

Used by companies like Vercel, OpenCode, and PayPal.

> _“OpenAPI codegen that just works.”_
>
> <sub>— Guillermo Rauch, CEO of Vercel</sub>

### Demo

<StackBlitz
  example="hey-api-example"
  openFile={[
    'openapi-ts.config.ts',
    'src/client/schemas.gen.ts',
    'src/client/sdk.gen.ts',
    'src/client/types.gen.ts',
  ]}
/>

## Features

- production-grade code that compiles
- runs in any Node.js 22+ environment
- accepts any OpenAPI specification
- core plugins for SDKs, types, and schemas
- HTTP clients for Fetch API, Angular, Axios, Next.js, Nuxt, and more
- 20+ plugins to reduce third-party boilerplate
- highly customizable via plugins
- [sync with Hey API Registry](/docs/openapi/typescript/integrations) for spec management

## Quick Start

The fastest way to use `@hey-api/openapi-ts` is via npx

```sh
npx @hey-api/openapi-ts -i hey-api/backend -o src/client
```

Congratulations on creating your first client! 🎉 You can learn more about the generated files on the [Output](/docs/openapi/typescript/output) page.

## Installation

You can download `@hey-api/openapi-ts` from npm using your favorite package manager.

<InstallCommand packageName="@hey-api/openapi-ts" />

### Versioning

This package is in [initial development](https://semver.org/#spec-item-4). Please pin an exact version so you can safely upgrade when you're ready.

We publish [migration notes](/docs/openapi/typescript/migrating) for every breaking release. You might not be impacted by a breaking change if you don't use the affected features.

## Usage

### CLI

Most people run `@hey-api/openapi-ts` via CLI. To do that, add a script to your `package.json` file which will make `openapi-ts` executable through script.

```json title="package.json"
"scripts": {
  "openapi-ts": "openapi-ts"
}
```

The above script can be executed by running `npm run openapi-ts` or equivalent command in other package managers. Next, we will create a [configuration](/docs/openapi/typescript/configuration) file and move our options from Quick Start to it.

### Node.js

You can also generate output programmatically by calling `createClient()` in a JavaScript/TypeScript file.

```ts title="script.ts"
import { createClient } from '@hey-api/openapi-ts';

createClient({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
});
```

### Vite

If you're using [Vite](https://vite.dev) 5, 6, 7, or 8, you can integrate `@hey-api/openapi-ts` directly into your build pipeline with `@hey-api/vite-plugin`. Install it alongside the main package:

<InstallCommand packageName="@hey-api/vite-plugin" />

Then add the plugin to your Vite configuration:

```ts title="vite.config.ts"
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    heyApiPlugin({
      config: {
        input: 'hey-api/backend', // sign up at app.heyapi.dev
        output: 'src/client',
      },
    }),
  ],
});
```

See the [Vite](/docs/openapi/typescript/configuration/vite) page for full configuration options.

### Configuration

It's a good practice to extract your configuration into a separate file. Learn how to do that and discover available options on the [Configuration](/docs/openapi/typescript/configuration) page.

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Integrations (`web/src/content/docs/docs/openapi/typescript/integrations.mdx`)

---
title: Hey API Platform
description: Automate your client generation with our OpenAPI specifications storage.
sidebar:
  label: GitHub
---

import { Code, Tabs, TabItem } from '@astrojs/starlight/components';

# Hey API Platform

:::caution
This feature is in development! 🎉 Try it out and provide feedback on [GitHub](https://github.com/orgs/hey-api/discussions/1773).
:::

You can automate your client generation with Hey API Platform thanks to reproducible builds. Create dependency links between your clients and APIs, and watch the magic unfold. It's completely language and codegen agnostic.

## Features

- API version history
- real-time updates
- reproducible builds
- language and codegen agnostic (TypeScript/Python/Go/Java/etc codegens are welcome)

## Upload Specifications

Before you can generate clients, you must publish your OpenAPI specifications to Hey API.

### Prerequisites

1. Create a **free account** with [Hey API](https://app.heyapi.dev).
1. Create a new **organization** and **project** for your API provider. We recommend your naming matches your GitHub structure as it will be referenced by API clients. For example, we are using **hey-api/backend** for the platform.
1. Inside your project, go to _Integrations_ > _APIs_ and generate an **API key**. Keep this value secret, it will be used to upload files.

### Add GitHub CI workflow

Once you have your API key, you can start uploading OpenAPI specifications on every API build. We'll use our [GitHub Action](https://github.com/marketplace/actions/upload-openapi-spec-by-hey-api), but you can also make the API call manually if you're not using GitHub.

Create a new GitHub workflow or add an upload step to an existing workflow inside your API codebase. The example below will upload your OpenAPI specification to Hey API on every pull request and push to the `main` branch.

```yaml title="github-workflow.yml"
name: Upload OpenAPI Specification

on:
  push:
    branches:
      - main
  pull_request:

jobs:
  upload-openapi-spec:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

      - name: Upload OpenAPI spec
        uses: hey-api/upload-openapi-spec@v1.3.0
        with:
          path-to-file: path/to/openapi.json
          tags: optional,custom,tags
        env:
          API_KEY: ${{ secrets.HEY_API_TOKEN }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### Inputs

To successfully upload an OpenAPI specification, you need to provide the following inputs (see `with` in the example above)

#### `path-to-file`

A relative path to your OpenAPI file within the repository. Note that you might need an additional step in your GitHub workflow to generate this file (see [FastAPI example](https://fastapi.tiangolo.com/how-to/extending-openapi/#generate-the-openapi-schema)).

#### `tags` (optional)

A comma-separated string value representing any custom tags you wish to add to your OpenAPI specification.

### Environment Variables

In addition to the required `path-to-file` input, you must provide the following environment variables.

#### `API_KEY`

This is the project API key you obtained from [Hey API](https://app.heyapi.dev).

:::caution
Personal API keys can't be used to upload specifications.
:::

#### `GITHUB_TOKEN`

This variable will be available inside your workflow by default. It's used to
fetch information about your repository, i.e., default branch.

## Generate Clients

You can generate clients from public projects or any private projects you can access. The setup is largely the same, you want to configure the input path used by your codegen.

<Tabs>
  <TabItem label="Hey API">
    <Code code="npx @hey-api/openapi-ts -i hey-api/backend -o src/client" lang="sh" />
  </TabItem>
  <TabItem label="OpenAPI TypeScript">
    <Code
      code={`npx openapi-typescript \\\r
    https://get.heyapi.dev/hey-api/backend \\\r
    -o schema.ts`}
      lang="sh"
    />
  </TabItem>
  <TabItem label="Orval">
    <Code
      code={`npx orval \\\r
    --input https://get.heyapi.dev/hey-api/backend \\\r
    --output ./src/client.ts`}
      lang="sh"
    />
  </TabItem>
  <TabItem label="Other">
    <Code
      code={`other-cli \\\r
    --input https://get.heyapi.dev/hey-api/backend \\\r
    --output refer/to/other/tools/docs`}
      lang="sh"
      meta="{2}"
    />
  </TabItem>
</Tabs>

By default, we preserve the current behavior and return the latest specification. Let's have a closer look at the input path and change that.

## Get API

As you can deduce from the examples above, the default command for fetching OpenAPI specifications looks like this.

```
https://get.heyapi.dev/<organization>/<project>
```

If you created an organization `foo` with project `bar` earlier, your URL would look like this.

```
https://get.heyapi.dev/foo/bar
```

### Auth

Projects are private by default, you will need to be authenticated to download OpenAPI specifications. We recommend using [project API keys](#prerequisites) in CI workflows and [personal API keys](https://app.heyapi.dev/settings/user/apis) for local development.

Once you have your API key, you can authenticate the request using the `Authorization` header or `api_key` query parameter.

```
https://get.heyapi.dev/foo/bar?api_key=<my_api_key>
```

Congratulations on fetching your first OpenAPI specification! 🎉

### Filters

The default behavior returns the last uploaded specification. This might not be what you want. You can use a range of filters to narrow down the possible specifications, or pin your builds to an exact version.

#### `branch`

You can fetch the last build from branch by providing the `branch` query parameter.

```
https://get.heyapi.dev/foo/bar?branch=production
```

#### `commit_sha`

You can fetch an exact specification by providing the `commit_sha` query parameter. This will always return the same file.

```
https://get.heyapi.dev/foo/bar?commit_sha=0eb34c2024841ce95620f3ec02a2fea164ea4e9d
```

#### `tags`

If you're tagging your specifications with [custom tags](#tags-optional), you can use them to filter the results. When you provide multiple tags, only the first match will be returned.

```
https://get.heyapi.dev/foo/bar?tags=optional,custom,tags
```

#### `version`

Every OpenAPI document contains a required version field. You can use this value to fetch the last uploaded specification matching the value.

```
https://get.heyapi.dev/foo/bar?version=1.0.0
```

## Feedback

We'd love your feedback! You can contact us on social media (search Hey API), [email](mailto:lubos@heyapi.dev), or [GitHub](https://github.com/orgs/hey-api/discussions/1773).

## Pricing

The platform is currently in beta with our focus being on delivering a great experience. We plan to announce pricing once we have gathered enough data around usage patterns. However, we can guarantee there will always be a free plan available. Our mission to bring the finest tooling for working with APIs remains unchanged.

---

### Web Src Content Docs Docs Openapi Typescript License (`web/src/content/docs/docs/openapi/typescript/license.md`)

---
title: License
description: License FAQ.
---

# License

### MIT License

Copyright (c) 2026-present Hey API

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

---

### Web Src Content Docs Docs Openapi Typescript Migrating (`web/src/content/docs/docs/openapi/typescript/migrating.mdx`)

---
title: Migrating
description: Migrating to @hey-api/openapi-ts.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';

# Migrating

Hey API is in active development, which allows us to move quickly and continuously improve the project. That pace sometimes comes with breaking changes. This page documents those changes and provides migration guidance for each release. If you need help with a migration, please [open an issue](https://github.com/hey-api/hey-api/issues).

## v0.99.0

### Plugin duplicates behavior

If you specified the same plugin multiple times, only the last instance would be used. We eventually added a warning for this behavior, but that didn't treat the root issue. This release changes that by merging duplicate plugin configurations.

### Renamed `plugin.symbols` to `plugin.imports`

To better represent its functionality, the `plugin.symbols` property has been renamed to `plugin.imports`.

### Removed `plugin.external()` function

This function was used to reference external symbols. All plugins now use the Imports API, which allows you to reference external symbols in a type-safe way through `plugin.imports`.

### Removed `plugin.registerSymbol()` function

This function was an alias for `plugin.symbol()` accepting a single argument. It has been removed in favor of `plugin.symbol()` which can now also accept a single argument.

## v0.98.0

### Declarative configuration

This is an internal change that simplifies the configuration and plugin APIs. The generated output should be unaffected, please [open an issue](https://github.com/hey-api/hey-api/issues) if that's not the case. If you have custom plugins, refer to the [custom plugin guide](/docs/openapi/typescript/plugins/custom) for the latest instructions.

## v0.97.0

### Changed `runtimeConfigPath` behavior

This was a known, long-standing issue confusing first-time users. Before, defining client `runtimeConfigPath` value would paste it verbatim to the generated output. This release changes the behavior to resolve relative to the output folder.

### Changed Ky client behavior

The Ky client was updated to be more intuitive. Some Ky options now need to be passed via the `kyOptions` field and you need to pass `undefined` to unset an option.

### Changed error interceptors behavior

Error interceptors now receive the result of the previous error interceptor. This aligns their behavior with request and response interceptors. This change only affects you if you use multiple interceptors.

### Optional client request and response

The returned request and response objects are now typed as optional. This aligns the types with the actual runtime behavior, which remains unchanged.

### Respect `throwOnError` option

Previously, there were instances where setting `throwOnError` to `false` would still throw an error. This most commonly happened when request validation failed. With this change, `throwOnError` is now truly respected.

## v0.96.0

### Removed Node 20 support

This release bumps the minimum required Node version to 22.13.

## v0.95.0

### Validator request schemas

Valibot and Zod plugins no longer export composite request `Data` schemas. Instead, each layer is exported as a separate schema. If you're using validators with SDKs, you can preserve the composite schema with `shouldExtract`:

<Tabs>
  <TabItem label="Zod">
```js {12-14} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'sdk',
      validator: 'zod',
    },
    {
      name: 'zod',
      requests: {
        shouldExtract: true,
      },
    },
  ],
};
```
  </TabItem>
  <TabItem label="Valibot">
```js {12-14} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'sdk',
      validator: 'valibot',
    },
    {
      name: 'valibot',
      requests: {
        shouldExtract: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Removed `plugin.getSymbol()` function

This function has been removed. You can use `plugin.querySymbol()` instead. It accepts the same arguments and returns the same result.

## v0.93.0

### Removed resolver node

Valibot and Zod plugins no longer expose the `enum.nodes.nullable` node. Both plugins were refactored so that nullable values are handled outside of resolvers.

## v0.92.0

### Updated Symbol interface

The `exportFrom` property has been replaced with the `getExportFromFilePath()` function. This allows you to dynamically determine export paths based on symbol properties. This is a low-level feature, so you're most likely unaffected.

## v0.91.0

### Removed CommonJS (CJS) support

`@hey-api/openapi-ts` is now ESM-only. This change simplifies the codebase, improves tree-shaking, and enables better integration with modern bundlers and TypeScript tooling.

CommonJS entry points (`require()`, `module.exports`) are no longer supported. If you are in a CJS environment, you can still load the package dynamically using `import()` like:

```js
const { defineConfig } = await import('@hey-api/openapi-ts');
```

If you have previously written:

```js
const { defineConfig } = require('@hey-api/openapi-ts');
```

Migrate by updating your static imports:

```js
import { defineConfig } from '@hey-api/openapi-ts';
```

If your environment cannot use ESM, pin to a previous version.

## v0.90.0

### Resolvers API

The [Resolvers API](/docs/openapi/typescript/plugins/concepts/resolvers) has been simplified and expanded to provide a more consistent behavior across plugins. You can view a few common examples on the [Resolvers](/docs/openapi/typescript/plugins/concepts/resolvers) page.

### Structure API

The [SDK plugin](/docs/openapi/typescript/plugins/sdk) and [Angular plugin](/docs/openapi/typescript/plugins/angular) now implement the Structure API, enabling more complex structures and fixing several known issues.

Some Structure APIs are incompatible with the previous configuration, most notably the `methodNameBuilder` function, which accepted the operation object as an argument. You can read the [SDK Output](/docs/openapi/typescript/plugins/sdk#output) section to familiarize yourself with the Structure API.

Please [open an issue](https://github.com/hey-api/hey-api/issues) if you're unable to migrate your configuration to the new syntax.

## v0.89.0

### Prefer named exports

This release changes the default for `index.ts` to prefer named exports. Named exports may lead to better IDE and bundler performance compared to asterisk (`*`) as your tooling doesn't have to inspect the underlying module to discover exports.

While this change is merely cosmetic, you can set `output.preferExportAll` to `true` if you prefer to use the asterisk.

```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    preferExportAll: true,
  },
};
```

### Removed `symbol:setValue:*` events

These events have been removed in favor of `node:set:*` events.

## v0.88.0

### Removed `compiler` and `tsc` exports

This release removes the `compiler` utility functions. Instead, it introduces a new TypeScript DSL exposed under the `$` symbol. All plugins now use this interface, so you may notice slight changes in the generated output.

## v0.87.0

### Removed legacy clients

This release removes support for legacy clients and plugins. Please migrate to the new clients if you haven't done so yet. If you're unable to do so due to a missing feature, let us know on [GitHub](https://github.com/hey-api/hey-api/issues).

## v0.86.0

### Removed Node 18 support

This release bumps the minimum required Node version to 20.19.

## v0.85.0

### Updated `output` options

We made the `output` configuration more consistent by using `null` to represent disabled options. This change does not affect boolean options.

```js ins={5,7,10} del={4,6,9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    format: false,
    format: null,
    lint: false,
    lint: null,
    path: 'src/client',
    tsConfigPath: 'off',
    tsConfigPath: null,
  },
};
```

### Updated Pinia Colada query options

Pinia Colada query options now use `defineQueryOptions` to improve reactivity support. Instead of calling the query options function, you can use one of the following approaches.

<Tabs>
  <TabItem label="no params">
```ts title="colada.gen.ts"
useQuery(getPetsQuery);
```
  </TabItem>
  <TabItem label="constant">
```ts title="colada.gen.ts"
useQuery(getPetByIdQuery, () => ({
  path: {
    petId: 1,
  },
}));
```
  </TabItem>
  <TabItem label="reactive">
```ts title="colada.gen.ts"
const petId = ref<number | null>(1);

useQuery(getPetByIdQuery, () => ({
  path: {
    petId: petId.value,
  },
}));
```
  </TabItem>
  <TabItem label="properties">
```ts title="colada.gen.ts"
const petId = ref<number | null>(1);

useQuery(() => ({
  ...getPetByIdQuery({
    path: { petId: petId.value as number },
  }),
  enabled: () => petId.value !== null,
}));
```
  </TabItem>
</Tabs>

## v0.84.0

### Symbol API

This release improves the Symbol API, which adds the capability to place symbols in arbitrary files. We preserved the previous output structure for all plugins except Angular.

You can preserve the previous Angular output by writing your own [placement function](/docs/openapi/typescript/configuration/parser#hooks-symbols).

### TypeScript renderer

We ship a dedicated TypeScript renderer for `.ts` files. This release improves the renderer's ability to group and sort imported modules, resulting in a more polished output.

### Removed `output` plugin option

Due to the Symbol API release, this option has been removed from the Plugin API.

## v0.83.0

### Symbol API

This release adds the Symbol API, which significantly reduces the risk of naming collisions. While the generated output should only include formatting changes, this feature introduces breaking changes to the Plugin API that affect custom plugins.

We will update the [custom plugin guide](/docs/openapi/typescript/plugins/custom) once the Plugin API becomes more stable.

### Removed `groupByTag` Pinia Colada option

This option has been removed to provide a more consistent API across plugins. We plan to bring it back in a future release.

## v0.82.0

### Hooks API

This release adds the [Hooks API](/docs/openapi/typescript/configuration/parser#hooks), giving you granular control over which operations generate queries and mutations. As a result, we tightened the previous behavior and POST operations no longer generate queries by default. To preserve the old behavior, add a custom matcher.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    hooks: {
      operations: {
        isQuery: (op) => (op.method === 'post' ? true : undefined),
      },
    },
  },
};
```

## v0.81.0

### Server-Sent Events (SSE)

This release adds support for server-sent events (SSE). Instead of treating `text/event-stream` content types as regular HTTP methods, we now generate SSE streams. In practice, you will want to update your affected endpoints to process streamed events.

<Tabs>
  <TabItem label="before">
```js title="client.gen.ts"
const { data } = await foo();
console.log(data.type);
```
  </TabItem>
  <TabItem label="after">
```js title="client.gen.ts"
const { stream } = await foo();
for await (const event of stream) {
  console.log(event.type);
}
```
  </TabItem>
</Tabs>

## v0.80.0

### Added Zod 4 and Zod Mini

This release adds support for Zod 4 and Zod Mini. By default, the `zod` plugin will generate output for Zod 4. If you want to preserve the previous output for Zod 3 or use Zod Mini, set `compatibilityVersion` to `3` or `mini`.

<Tabs>
  <TabItem label="Zod 3">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
    },
  ],
};
```
  </TabItem>
  <TabItem label="Zod Mini">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
    },
  ],
};
```
  </TabItem>
</Tabs>

## v0.79.0

### Removed `typescript+namespace` enums mode

Due to a simpler TypeScript plugin implementation, the `typescript+namespace` enums mode is no longer necessary. This mode was used in the past to group inline enums under the same namespace. With the latest changes, this behavior is no longer supported. You can either choose to ignore inline enums (default), or use the `enums` transform (added in v0.78.0) to convert them into reusable components which will get exported as usual.

## v0.78.0

### Added `parser` options

Previously, `@hey-api/typescript` would generate correct types, but the validator plugins would have to re-implement the same logic or generate schemas that didn't match the generated types.

Since neither option was ideal, this release adds a dedicated place for `parser` options. Parser is responsible for preparing the input so plugins can generate more accurate output with less effort.

You can learn more about configuring parser on the [Parser](/docs/openapi/typescript/configuration/parser) page.

### Moved `input` options

The following options were moved to the new `parser` group.

- `input.filters` moved to `parser.filters`
- `input.pagination` moved to `parser.pagination`
- `input.patch` moved to `parser.patch`
- `input.validate_EXPERIMENTAL` moved to `parser.validate_EXPERIMENTAL`

### Updated `typescript` options

The following options were renamed.

- `enumsCase` moved to `enums.case`
- `enumsConstantsIgnoreNull` moved to `enums.constantsIgnoreNull`

### Moved `typescript` options

The following options were moved to the new `parser` group.

- `exportInlineEnums` moved to `parser.transforms.enums`
- `readOnlyWriteOnlyBehavior` moved to `parser.transforms.readWrite.enabled`
- `readableNameBuilder` moved to `parser.transforms.readWrite.responses.name`
- `writableNameBuilder` moved to `parser.transforms.readWrite.requests.name`

### Updated `readWrite.responses` name

Additionally, the naming pattern for response schemas has changed from `{name}Readable` to `{name}`. This is to prevent your code from breaking by default when using a schema that gets updated with a write-only field.

## v0.77.0

### Updated `sdk.validator` option

Clients can now validate both request and response data. As a result, passing a boolean or string to `validator` will control both of these options. To preserve the previous behavior, set `validator.request` to `false` and `validator.response` to your previous configuration.

```js ins={9-12} del={8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      validator: true,
      validator: {
        request: false,
        response: true,
      },
    },
  ],
};
```

### Updated Plugin API

Please refer to the [custom plugin](/docs/openapi/typescript/plugins/custom) tutorial for the latest guide.

## v0.76.0

### Single Valibot schema per request

Previously, we generated a separate schema for each endpoint parameter and request body. In v0.76.0, a single request schema is generated for the whole endpoint. It may contain a request body, parameters, and headers.

```ts
const vData = v.object({
  body: v.optional(
    v.object({
      foo: v.optional(v.string()),
      bar: v.optional(v.union([v.number(), v.null()])),
    }),
  ),
  headers: v.optional(v.never()),
  path: v.object({
    baz: v.string(),
  }),
  query: v.optional(v.never()),
});
```

If you need to access individual fields, you can do so using the [`.entries`](https://valibot.dev/api/object/) API. For example, we can get the request body schema with `vData.entries.body`.

## v0.75.0

### Updated TanStack Query options

The TanStack Query plugin options have been expanded to support more naming and casing patterns. As a result, the following options have been renamed.

- `queryOptionsNameBuilder` renamed to `queryOptions`
- `infiniteQueryOptionsNameBuilder` renamed to `infiniteQueryOptions`
- `mutationOptionsNameBuilder` renamed to `mutationOptions`
- `queryKeyNameBuilder` renamed to `queryKeys`
- `infiniteQueryKeyNameBuilder` renamed to `infiniteQueryKeys`

### Added `plugin.forEach()` method

This method replaces the `.subscribe()` method. Additionally, `.forEach()` is executed immediately, which means we don't need the `before` and `after` events – simply move your code before and after the `.forEach()` block.

```ts del={1-4} ins={5}
plugin.subscribe('operation', (event) => {
  // do something with event
});
plugin.subscribe('schema', (event) => {
plugin.forEach('operation', 'schema', (event) => {
  // do something with event
});
```

## v0.74.0

### Single Zod schema per request

Previously, we generated a separate schema for each endpoint parameter and request body. In v0.74.0, a single request schema is generated for the whole endpoint. It may contain a request body, parameters, and headers.

```ts
const zData = z.object({
  body: z
    .object({
      foo: z.string().optional(),
      bar: z.union([z.number(), z.null()]).optional(),
    })
    .optional(),
  headers: z.never().optional(),
  path: z.object({
    baz: z.string(),
  }),
  query: z.never().optional(),
});
```

If you need to access individual fields, you can do so using the [`.shape`](https://zod.dev/api?id=shape) API. For example, we can get the request body schema with `zData.shape.body`.

## v0.73.0

### Bundle `@hey-api/client-*` plugins

In previous releases, you had to install a separate client package to generate a fully working output, e.g., `npm install @hey-api/client-fetch`. This created a few challenges: getting started was slower, upgrading was sometimes painful, and bundling too. Beginning with v0.73.0, all Hey API clients are bundled by default and don't require installing any additional dependencies. You can remove any installed client packages and re-run `@hey-api/openapi-ts`.

```sh
npm uninstall @hey-api/client-fetch
```

## v0.72.0

### Added `sdk.classStructure` option

When generating class-based SDKs, we now try to infer the ideal structure using `operationId` keywords. If you'd like to preserve the previous behavior, set `classStructure` to `off`.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      classStructure: 'off',
      name: '@hey-api/sdk',
    },
  ],
};
```

## v0.71.0

### Renamed `sdk.serviceNameBuilder` option

This option has been renamed to `sdk.classNameBuilder` to better represent its functionality. Additionally, it's no longer set by default. To preserve the previous behavior, update your configuration.

```js ins={7} del={9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      classNameBuilder: '{{name}}Service',
      name: '@hey-api/sdk',
      serviceNameBuilder: '{{name}}Service',
    },
  ],
};
```

## v0.68.0

### Upgraded input filters

Input filters now avoid generating invalid output without requiring you to specify every missing schema as in the previous releases. As part of this release, we changed the way filters are configured and removed the support for regular expressions. Let us know if regular expressions are still useful for you and want to bring them back!

<Tabs>
  <TabItem label="include">
```js {6,9} del={12} title="openapi-ts.config.ts"
export default {
  input: {
    // match only the schema named `foo` and `GET` operation for the `/api/v1/foo` path
    filters: {
      operations: {
        include: ['GET /api/v1/foo'],
      },
      schemas: {
        include: ['foo'],
      },
    },
    include: '^(#/components/schemas/foo|#/paths/api/v1/foo/get)$',
    path: 'hey-api/backend', // sign up at app.heyapi.dev
  },
  output: 'src/client',
  plugins: ['@hey-api/client-fetch'],
};
```
  </TabItem>
  <TabItem label="exclude">
```js {7,10} del={4} title="openapi-ts.config.ts"
export default {
  input: {
    // match everything except for the schema named `foo` and `GET` operation for the `/api/v1/foo` path
    exclude: '^(#/components/schemas/foo|#/paths/api/v1/foo/get)$',
    filters: {
      operations: {
        exclude: ['GET /api/v1/foo'],
      },
      schemas: {
        exclude: ['foo'],
      },
    },
    path: 'hey-api/backend', // sign up at app.heyapi.dev
  },
  output: 'src/client',
  plugins: ['@hey-api/client-fetch'],
};
```
  </TabItem>
</Tabs>

## v0.67.0

### Respecting `moduleResolution` value in `tsconfig.json`

This release introduces functionality related to your `tsconfig.json` file. The initial feature properly respects the value of your `moduleResolution` field. If you're using `nodenext`, the relative module paths in your output will be appended with `.js`. To preserve the previous behavior where we never appended `.js` to relative module paths, set `output.tsConfigPath` to `off`.

```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    tsConfigPath: 'off',
  },
};
```

## v0.66.0

### Read-only and write-only fields

Starting with v0.66.0, `@hey-api/typescript` will generate separate types for payloads and responses if it detects any read-only or write-only fields. To preserve the previous behavior and generate a single type regardless, set `readOnlyWriteOnlyBehavior` to `off`.

```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/typescript',
      readOnlyWriteOnlyBehavior: 'off',
    },
  ],
};
```

## v0.64.0

### Added `ClientOptions` interface

The `Config` interface now accepts an optional generic extending `ClientOptions` instead of `boolean` type `ThrowOnError`.

```ts del={1} ins={2}
type Foo = Config<false>;
type Foo = Config<{ throwOnError: false }>;
```

### Added `client.baseUrl` option

You can use this option to configure the default base URL for the generated client. By default, we will attempt to resolve the first defined server or infer the base URL from the input path. If you'd like to preserve the previous behavior, set `baseUrl` to `false`.

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      baseUrl: false,
      name: '@hey-api/client-fetch',
    },
  ],
};
```

## v0.63.0

### Client plugins

Clients are now plugins generating their own `client.gen.ts` file. There's no migration needed if you're using CLI. If you're using the configuration file, move `client` options to `plugins`.

```js del={2} ins={5} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-fetch'],
};
```

### Added `client.gen.ts` file

Related to above, the internal `client` instance previously located in `sdk.gen.ts` is now defined in `client.gen.ts`. If you're importing it in your code, update the import module.

```js del={1} ins={2}
import { client } from 'client/sdk.gen';
import { client } from 'client/client.gen';
```

### Moved `sdk.throwOnError` option

This SDK configuration option has been moved to the client plugins where applicable. Not every client can be configured to throw on error, so it didn't make sense to expose the option when it didn't have any effect.

```js ins={7} del={11} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-fetch',
      throwOnError: true,
    },
    {
      name: '@hey-api/sdk',
      throwOnError: true,
    },
  ],
};
```

## v0.62.0

### Changed parser

Formerly known as the experimental parser, this is now the default parser. This change should not impact the generated output's functionality. However, there might be cases where this results in breaking changes due to different handling of certain scenarios. If you need to revert to the legacy parser, set the `experimentalParser` flag to `false`.

```js {3} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  experimentalParser: false,
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```

Note that the legacy parser is no longer supported and will be removed in the v1 release.

## v0.61.0

### Added `auth` option

Client package functions `accessToken` and `apiKey` were replaced with a single `auth` function for fetching auth tokens. If your API supports multiple auth mechanisms, you can use the `auth` argument to return the appropriate token.

```js del={4-5} ins={6}
import { client } from 'client/sdk.gen';

client.setConfig({
  accessToken: () => '<my_token>',
  apiKey: () => '<my_token>',
  auth: (auth) => '<my_token>',
});
```

Due to conflict with the Axios native `auth` option, we removed support for configuring Axios auth. Please let us know if you require this feature added back.

### Added `watch` option

While this is a new feature, supporting it involved replacing the `@apidevtools/json-schema-ref-parser` dependency with our own implementation. Since this was a big change, we're applying caution and marking this as a breaking change.

### Changed `parseAs: 'auto'` behavior

The Fetch API client will return raw response body as `ReadableStream` when `Content-Type` response header is undefined and `parseAs` is `auto`.

## v0.60.0

### Added `sdk.transformer` option

When generating SDKs, you now have to specify `transformer` in order to modify response data. By default, adding `@hey-api/transformers` to your plugins will only produce additional output. To preserve the previous functionality, set `sdk.transformer` to `true`.

```js {13} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      dates: true,
      name: '@hey-api/transformers',
    },
    {
      name: '@hey-api/sdk',
      transformer: true,
    },
  ],
};
```

## v0.59.0

### Added `logs.level` option

You can now configure different log levels. As part of this feature, we had to introduce a breaking change by moving the `debug` option to `logs.level`. This will affect you if you're calling `@hey-api/openapi-ts` from Node.js (not CLI) or using the configuration file.

```js del={3} ins={6} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  debug: true,
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  logs: {
    level: 'debug',
  },
  output: 'src/client',
};
```

### Updated default `plugins`

`@hey-api/schemas` has been removed from the default plugins. To continue using it, add it to your plugins array.

```js {8} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  experimentalParser: true,
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@hey-api/schemas',
  ],
};
```

## v0.58.0

### Removed `schemas.gen.ts` re-export

`index.ts` will no longer re-export `schemas.gen.ts` to reduce the chance of producing broken output. Please update your code to import from `schemas.gen.ts` directly.

```js del={1} ins={2}
import { mySchema } from 'client';
import { mySchema } from 'client/schemas.gen';
```

### Removed `transformers.gen.ts` re-export

`index.ts` will no longer re-export `transformers.gen.ts` to reduce the chance of producing broken output. Please update your code to import from `transformers.gen.ts` directly.

```js del={1} ins={2}
import { myTransformer } from 'client';
import { myTransformer } from 'client/transformers.gen';
```

### Added `output.clean` option

By default, the `output.path` folder will be emptied on every run. To preserve the previous behavior, set `output.clean` to `false`.

```js {5} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    clean: false,
    path: 'src/client',
  },
};
```

### Added `typescript.identifierCase` option

**This change affects only the experimental parser.** By default, the generated TypeScript interfaces will follow the PascalCase naming convention. In the previous versions, we tried to preserve the original name as much as possible. To keep the previous behavior, set `typescript.identifierCase` to `preserve`.

```js {9} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  experimentalParser: true,
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      identifierCase: 'preserve',
      name: '@hey-api/typescript',
    },
  ],
};
```

## v0.57.0

### Renamed `@hey-api/services` plugin

This plugin has been renamed to `@hey-api/sdk`.

### Changed `sdk.output` value

To align with the updated name, the `@hey-api/sdk` plugin will generate an `sdk.gen.ts` file. This will result in a breaking change if you're importing from `services.gen.ts`. Please update your imports to reflect this change.

```js del={1} ins={2}
import { client } from 'client/services.gen';
import { client } from 'client/sdk.gen';
```

### Renamed `@hey-api/types` plugin

This plugin has been renamed to `@hey-api/typescript`.

### Added `typescript.exportInlineEnums` option

By default, inline enums (enums not defined as reusable components in the input file) will be generated only as inlined union types. You can set `exportInlineEnums` to `true` to treat inline enums as reusable components. When `true`, the exported enums will follow the style defined in `enums`.

This is a breaking change since in the previous versions, inline enums were always treated as reusable components. To preserve your current output, set `exportInlineEnums` to `true`. This feature works only with the experimental parser.

```js {9} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  experimentalParser: true,
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      exportInlineEnums: true,
      name: '@hey-api/typescript',
    },
  ],
};
```

## v0.56.0

### Deprecated `tree` in `@hey-api/types`

This config option is deprecated and will be removed when the experimental parser becomes the default.

## v0.55.0

This release adds the ability to filter your OpenAPI specification before it's processed. This feature will be useful if you are working with a large specification and are interested in generating output only from a small subset.

This feature is available only in the experimental parser. In the future, this will become the default parser. To opt-in to the experimental parser, set the `experimentalParser` flag in your configuration to `true`.

### Deprecated `include` in `@hey-api/types`

This config option is deprecated and will be removed when the experimental parser becomes the default.

### Deprecated `filter` in `@hey-api/services`

This config option is deprecated and will be removed when the experimental parser becomes the default.

### Added `input.include` option

This config option can be used to replace the deprecated options. It accepts a regular expression string matching against references within the bundled specification.

```js {5} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  experimentalParser: true,
  input: {
    include: '^(#/components/schemas/foo|#/paths/api/v1/foo/get)$',
    path: 'hey-api/backend', // sign up at app.heyapi.dev
  },
  output: 'src/client',
};
```

The configuration above will process only the schema named `foo` and `GET` operation for the `/api/v1/foo` path.

## v0.54.0

This release makes plugins first-class citizens. In order to achieve that, the following breaking changes were introduced.

### Removed CLI options

The `--types`, `--schemas`, and `--services` CLI options have been removed. You can list which plugins you'd like to use explicitly by passing a list of plugins as `--plugins <plugin1> <plugin2>`

### Removed `*.export` option

Previously, you could explicitly disable export of certain artifacts using the `*.export` option or its shorthand variant. These were both removed. You can now disable export of specific artifacts by manually defining an array of `plugins` and excluding the unwanted plugin.

<Tabs>
  <TabItem label="shorthand">
```js ins={6} del={5} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  schemas: false,
  plugins: ['@hey-api/types', '@hey-api/services'],
};
```
  </TabItem>
  <TabItem label="exclude">
```js ins={8} del={6} title="*.export"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  schemas: {
    export: false,
  },
  plugins: ['@hey-api/types', '@hey-api/services'],
};
```
  </TabItem>
</Tabs>

### Renamed `schemas.name` option

Each plugin definition contains a `name` field. This was conflicting with the `schemas.name` option. As a result, it has been renamed to `nameBuilder`.

```js del={6} ins={11} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  schemas: {
    name: (name) => `${name}Schema`,
  },
  plugins: [
    // ...other plugins
    {
      nameBuilder: (name) => `${name}Schema`,
      name: '@hey-api/schemas',
    },
  ],
};
```

### Removed `services.include` shorthand option

Previously, you could use a string value as a shorthand for the `services.include` configuration option. You can now achieve the same result using the `include` option.

```js del={5} ins={9} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  services: '^MySchema',
  plugins: [
    // ...other plugins
    {
      include: '^MySchema',
      name: '@hey-api/services',
    },
  ],
};
```

### Renamed `services.name` option

Each plugin definition contains a `name` field. This was conflicting with the `services.name` option. As a result, it has been renamed to `serviceNameBuilder`.

```js del={6} ins={11} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  services: {
    name: '{{name}}Service',
  },
  plugins: [
    // ...other plugins
    {
      serviceNameBuilder: '{{name}}Service',
      name: '@hey-api/services',
    },
  ],
};
```

### Renamed `types.dates` option

Previously, you could set `types.dates` to a boolean or a string value, depending on whether you wanted to transform only type strings into dates, or runtime code too. Many people found these options confusing, so they have been simplified to a boolean and extracted into a separate `@hey-api/transformers` plugin.

```js del={6} ins={11} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  types: {
    dates: 'types+transform',
  },
  plugins: [
    // ...other plugins
    {
      dates: true,
      name: '@hey-api/transformers',
    },
  ],
};
```

### Removed `types.include` shorthand option

Previously, you could use a string value as a shorthand for the `types.include` configuration option. You can now achieve the same result using the `include` option.

```js del={5} ins={9} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  types: '^MySchema',
  plugins: [
    // ...other plugins
    {
      include: '^MySchema',
      name: '@hey-api/types',
    },
  ],
};
```

### Renamed `types.name` option

Each plugin definition contains a `name` field. This was conflicting with the `types.name` option. As a result, it has been renamed to `style`.

```js del={6} ins={12} title="openapi-ts.config.ts"
export default {
  client: '@hey-api/client-fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  types: {
    name: 'PascalCase',
  },
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/types',
      style: 'PascalCase',
    },
  ],
};
```

## v0.53.0

### Changed schemas name pattern

Previously, generated schemas would have their definition names prefixed with `$`. This was problematic when using them with Svelte due to reserved keyword conflicts. The new naming pattern for schemas suffixes their definition names with `Schema`. You can continue using the previous pattern by setting the `schemas.name` configuration option.

```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  schemas: {
    name: (name) => `$${name}`,
  },
};
```

### Renamed legacy clients

Legacy clients were renamed to signal they are deprecated more clearly. To continue using legacy clients, you will need to update your configuration and prefix them with `legacy/`.

<Tabs>
  <TabItem label="fetch">
```js ins={3} del={2} title="openapi-ts.config.ts"
export default {
  client: 'fetch',
  client: 'legacy/fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
  <TabItem label="axios">
```js ins={3} del={2} title="openapi-ts.config.ts"
export default {
  client: 'axios',
  client: 'legacy/axios',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
  <TabItem label="angular">
```js ins={3} del={2} title="openapi-ts.config.ts"
export default {
  client: 'angular',
  client: 'legacy/angular',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
  <TabItem label="node">
```js ins={3} del={2} title="openapi-ts.config.ts"
export default {
  client: 'node',
  client: 'legacy/node',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
  <TabItem label="xhr">
```js ins={3} del={2} title="openapi-ts.config.ts"
export default {
  client: 'xhr',
  client: 'legacy/xhr',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```
  </TabItem>
</Tabs>

## v0.52.0

### Removed internal `client` export

Previously, client packages would create a default client which you'd then import and configure.

```js
import { client, createClient } from '@hey-api/client-fetch';

createClient({
  baseUrl: 'https://example.com',
});

console.log(client.getConfig().baseUrl); // <-- 'https://example.com'
```

This client instance was used internally by services unless overridden. Apart from running `createClient()` twice, people were confused about the meaning of `global` configuration option.

Starting with v0.52.0, client packages will not create a default client. Instead, services will define their own client. You can now achieve the same configuration by importing `client` from services and using the new `setConfig()` method.

```js
import { client } from 'client/services.gen';

client.setConfig({
  baseUrl: 'https://example.com',
});

console.log(client.getConfig().baseUrl); // <-- 'https://example.com'
```

## v0.51.0

### Required `client` option

Client now has to be explicitly specified and `@hey-api/openapi-ts` will no longer generate a legacy Fetch API client by default. To preserve the previous default behavior, set the `client` option to `fetch`.

```js {2} title="openapi-ts.config.ts"
export default {
  client: 'fetch',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```

## v0.48.0

### Changed `methodNameBuilder()` signature

The `services.methodNameBuilder()` function now provides a single `operation` argument instead of multiple cherry-picked properties from it.

```js del={7} ins={8} title="openapi-ts.config.ts"
import { createClient } from '@hey-api/openapi-ts';

createClient({
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  services: {
    methodNameBuilder: (service, name) => name,
    methodNameBuilder: (operation) => operation.name,
  },
});
```

## v0.46.0

### Tree-shakeable services

By default, your services will now support [tree-shaking](https://developer.mozilla.org/docs/Glossary/Tree_shaking). You can either use wildcard imports

```js del={1} ins={2}
import { DefaultService } from 'client/services.gen';
import * as DefaultService from 'client/services.gen';

DefaultService.foo(); // only import needs to be changed
```

or update all references to service classes

```js del={1} ins={2}
import { DefaultService } from 'client/services.gen';
import { foo } from 'client/services.gen';

foo(); // all references need to be changed
```

If you want to preserve the old behavior, you can set the newly exposed `services.asClass` option to `true.`

```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  services: {
    asClass: true,
  },
};
```

## v0.45.0

### Removed `client` inference

`@hey-api/openapi-ts` will no longer infer which client you want to generate. By default, we will create a `fetch` client. If you want a different client, you can specify it using the `client` option.

```js {2} title="openapi-ts.config.ts"
export default {
  client: 'axios',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
};
```

## v0.44.0

### Moved `format`

This config option has been moved. You can now configure formatter using the `output.format` option.

```js del={2} ins={5} title="openapi-ts.config.ts"
export default {
  format: 'prettier',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    format: 'prettier',
    path: 'src/client',
  },
};
```

### Moved `lint`

This config option has been moved. You can now configure linter using the `output.lint` option.

```js del={3} ins={5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  lint: 'eslint',
  output: {
    lint: 'eslint',
    path: 'src/client',
  },
};
```

## v0.43.0

### Removed `enums.gen.ts`

This file has been removed. Instead, enums are exported from `types.gen.ts`. If you use imports from `enums.gen.ts`, you should be able to easily find and replace all instances.

```js del={1} ins={2}
import { Foo } from 'client/enums.gen';
import { Foo } from 'client/types.gen';
```

### Removed `Enum` postfix

Generated enum names are no longer postfixed with `Enum`. You can either alias your imports

```js del={1} ins={2}
import { FooEnum } from 'client/types.gen';
import { Foo as FooEnum } from 'client/types.gen';

console.log(FooEnum.value); // only import needs to be changed
```

or update all references to enums

```js del={1} ins={2}
import { FooEnum } from 'client/types.gen';
import { Foo } from 'client/types.gen';

console.log(Foo.value); // all references need to be changed
```

### Moved `enums`

This config option has been moved. You can now configure enums using the `types.enums` option.

```js del={2} ins={6} title="openapi-ts.config.ts"
export default {
  enums: 'javascript',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  types: {
    enums: 'javascript',
  },
};
```

## v0.42.0

### Changed `format`

This config option has changed. You now need to specify a value (`biome` or `prettier`) to format the output (default: `false`).

```js {2}
export default {
  format: 'prettier',
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
}
```

### Changed `lint`

This config option has changed. You now need to specify a value (`biome` or `eslint`) to lint the output (default: `false`).

```js {3}
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  lint: 'eslint',
  output: 'src/client',
}
```

### Moved `operationId`

This config option has been moved. You can now configure it using the `services.operationId` option.

```js {5}
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  services: {
    operationId: true,
  },
}
```

## v0.41.0

### Removed `postfixServices`

This config option has been removed. You can now transform service names using the string pattern parameter.

```js {5}
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  services: {
    name: 'myAwesome{{name}}Api',
  },
}
```

### Removed `serviceResponse`

This config option has been removed. You can now configure service responses using the `services.response` option.

```js {5}
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  services: {
    response: 'body',
  },
}
```

### Removed `useDateType`

This config option has been removed. You can now configure date type using the `types.dates` option.

```js {5}
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  type: {
    dates: true,
  },
}
```

## v0.40.0

### Renamed `models.gen.ts` file

`models.gen.ts` is now called `types.gen.ts`. If you use imports from `models.gen.ts`, you should be able to easily find and replace all instances.

```js del={1} ins={2}
import type { Model } from 'client/models.gen';
import type { Model } from 'client/types.gen';
```

### Renamed `exportModels`

This config option is now called `types`.

### PascalCase for types

You can now choose to export types using the PascalCase naming convention.

```js {5}
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  types: {
    name: 'PascalCase',
  },
}
```

### Exported `enums.gen.ts` file

Enums are now re-exported from the main `index.ts` file.

## v0.39.0

### Single `enums.gen.ts` file

Enums are now exported from a separate file. If you use imports from `models.ts`, you can change them to `enums.gen.ts`.

```js del={1} ins={2}
import { Enum } from 'client/models';
import { Enum } from 'client/enums.gen';
```

### Renamed `models.ts` file

`models.ts` is now called `models.gen.ts`. If you use imports from `models.ts`, you should be able to easily find and replace all instances.

```js del={1} ins={2}
import type { Model } from 'client/models';
import type { Model } from 'client/models.gen';
```

### Renamed `schemas.ts` file

`schemas.ts` is now called `schemas.gen.ts`. If you use imports from `schemas.ts`, you should be able to easily find and replace all instances.

```js del={1} ins={2}
import { $Schema } from 'client/schemas';
import { $Schema } from 'client/schemas.gen';
```

### Renamed `services.ts` file

`services.ts` is now called `services.gen.ts`. If you use imports from `services.ts`, you should be able to easily find and replace all instances.

```js del={1} ins={2}
import { DefaultService } from 'client/services';
import { DefaultService } from 'client/services.gen';
```

### Deprecated exports from `index.ts`

Until this release, `index.ts` file exported all generated artifacts. Starting from this release, enums are no longer exported from `index.ts`. Models, schemas, and services will continue to be exported from `index.ts` to avoid a huge migration lift, but we recommend migrating to import groups per artifact type.

```js del={1} ins={2-5}
import { Enum, type Model, $Schema, DefaultService } from 'client';
import { Enum } from 'client/enums.gen';
import type { Model } from 'client/models.gen';
import { $Schema } from 'client/schemas.gen';
import { DefaultService } from 'client/services.gen';
```

### Prefer `unknown`

Types that cannot be determined will now be generated as `unknown` instead of `any`. To dismiss any errors, you can cast your variables back to `any`, but we recommend updating your code to work with `unknown` types.

```js
const foo = bar as any
```

## v0.38.0

### Renamed `write`

This config option is now called `dryRun` (file) or `--dry-run` (CLI). To restore existing functionality, invert the value, ie. `write: true` is `dryRun: false` and `write: false` is `dryRun: true`.

## v0.36.0

### JSON Schema 2020-12

Schemas are exported directly from OpenAPI specification. This means your schemas might change depending on which OpenAPI version you're using. If this release caused a field to be removed, consult the JSON Schema documentation on how to obtain the same value from JSON Schema (e.g., [required properties](https://json-schema.org/understanding-json-schema/reference/object#required)).

### Renamed `exportSchemas`

This config option is now called `schemas`.

## v0.35.0

### Removed `postfixModels`

This config option has been removed.

## v0.34.0

### Single `services.ts` file

Services are now exported from a single file. If you used imports from individual service files, these will need to be updated to refer to the single `services.ts` file.

## v0.31.1

### Merged enums options

`useLegacyEnums` config option is now `enums: 'typescript'` and existing `enums: true` option is now `enums: 'javascript'`.

## v0.31.0

### Single `models.ts` file

TypeScript interfaces are now exported from a single file. If you used imports from individual model files, these will need to be updated to refer to the single `models.ts` file.

### Single `schemas.ts` file

Schemas are now exported from a single file. If you used imports from individual schema files, these will need to be updated to refer to the single `schemas.ts` file.

## v0.27.38

### `useOptions: true`

By default, generated clients will use a single object argument to pass values to API calls. This is a significant change from the previous default of unspecified array of arguments. If migrating your application in one go isn't feasible, we recommend deprecating your old client and generating a new client.

```ts
import { DefaultService } from 'client/services'; // <-- old client with array arguments

import { DefaultService } from 'client_v2/services'; // <-- new client with options argument
```

This way, you can gradually switch over to the new syntax as you update parts of your code. Once you've removed all instances of `client` imports, you can safely delete the old `client` folder and find and replace all `client_v2` calls to `client`.

## v0.27.36

### `exportSchemas: true`

By default, we will create schemas from your OpenAPI specification. Use `exportSchemas: false` to preserve the old behavior.

## v0.27.32

### Renamed `Config` interface

This interface is now called `UserConfig`.

## v0.27.29

### Renamed `openapi` CLI command

This command is now called `openapi-ts`.

## v0.27.26

### Removed `indent`

This config option has been removed. Use a [code formatter](/docs/openapi/typescript/configuration/output#post-process) to modify the generated files code style according to your preferences.

## v0.27.24

### Removed `useUnionTypes`

This config option has been removed. Generated types will behave the same as `useUnionTypes: true` before.

## OpenAPI TypeScript Codegen

`@hey-api/openapi-ts` was originally forked from Ferdi Koomen's [openapi-typescript-codegen](https://github.com/ferdikoomen/openapi-typescript-codegen). Therefore, we want you to be able to migrate your projects. Migration should be relatively straightforward if you follow the release notes on this page. Start on [v0.27.24](#v0-27-24) and scroll to the release you're migrating to.

---

### Web Src Content Docs Docs Openapi Typescript Mocks (`web/src/content/docs/docs/openapi/typescript/mocks.mdx`)

---
title: Testing
description: Learn about testing with @hey-api/openapi-ts.
sidebar:
  label: Overview
---

import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

# Testing

Testing is an important component of every robust development process. Generate realistic mock data, intercept requests at the network layer, or drive assertions against a running server, all from your specification.

## Plugins

Hey API natively supports the following testing libraries.

- [Chance](/docs/openapi/typescript/plugins/chance) <Badge text="Vote" variant="tip" />
- [Faker](/docs/openapi/typescript/plugins/faker) <Badge text="Vote" variant="tip" />
- [Falso](/docs/openapi/typescript/plugins/falso) <Badge text="Vote" variant="tip" />
- [MSW](/docs/openapi/typescript/plugins/msw) <Badge text="Vote" variant="tip" />
- [Nock](/docs/openapi/typescript/plugins/nock) <Badge text="Vote" variant="tip" />
- [Playwright](/docs/openapi/typescript/plugins/playwright) <Badge text="Vote" variant="tip" />
- [Supertest](/docs/openapi/typescript/plugins/supertest) <Badge text="Vote" variant="tip" />

Don't see your library? Let us know by [opening an issue](https://github.com/hey-api/hey-api/issues).

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Output (`web/src/content/docs/docs/openapi/typescript/output.mdx`)

---
title: Output
description: Learn about files generated with @hey-api/openapi-ts.
---

import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

# Output

Every generated file in your output folder is created by a plugin. This page describes the default output, but similar logic applies to all plugins.

## Overview

If you use the default configuration, your [project](https://stackblitz.com/edit/hey-api-example?file=openapi-ts.config.ts,src%2Fclient%2Fschemas.gen.ts,src%2Fclient%2Fsdk.gen.ts,src%2Fclient%2Ftypes.gen.ts) might look like this.

<FileTree>
- my-app/
  - node_modules/
  - src/
    - client/
      - client/
      - core/
      - client.gen.ts
      - index.ts
      - sdk.gen.ts
      - types.gen.ts
    - index.ts
  - package.json
</FileTree>

Your actual output depends on your Hey API configuration. It may contain a different number of files and their contents might differ.

Let's go through each file in the `src/client` folder and explain what it looks like, what it does, and how to use it.

## Client

`client.gen.ts` is generated by [client plugins](/docs/openapi/typescript/clients). If you choose to generate SDKs (enabled by default), we use the Fetch client unless specified otherwise.

```ts title="client.gen.ts"
import { createClient, createConfig } from './client';

export const client = createClient(createConfig());
```

The contents of this file are consumed by SDKs, but you can also import `client` in your application to perform additional configuration or send manual requests.

### Bundle

Client plugins provide their bundles inside `client` and `core` folders. The contents of these folders don't depend on the provided input. Everything inside these folders serves as a scaffolding so the generated code can make HTTP requests.

## TypeScript

You can learn more on the [TypeScript](/docs/openapi/typescript/plugins/typescript) page.

## SDK

You can learn more on the [SDK](/docs/openapi/typescript/plugins/sdk) page.

## Entry File

`index.ts` is not generated by any specific plugin. It's meant for convenience and by default, it re-exports every artifact generated by default plugins (TypeScript and SDK).

```ts title="index.ts"
export * from './sdk.gen';
export * from './types.gen';
```

### Disable entry file

We recommend importing artifacts from their respective files to avoid ambiguity, but we leave this choice up to you.

```ts title="index.ts"
import type { Pet } from './client';
// or
import type { Pet } from './client/types.gen';
```

If you're not importing artifacts from the entry file, you can skip generating it altogether by setting the `output.entryFile` option to `false`.

```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    entryFile: false,
    path: 'src/client',
  },
};
```

### Re-export artifacts

You can choose which artifacts should be re-exported from the entry file using the `includeInEntry` option on any plugin. For example, we can re-export all [Zod](/docs/openapi/typescript/plugins/zod) plugin artifacts by setting `includeInEntry` to `true`:

<Tabs>
  <TabItem label="example">
```ts title="index.ts"
export {
  zAddPetData,
  zAddPetResponse,
  zApiResponse,
  zCategory,
  // ...more exports
} from './zod.gen';
```
  </TabItem>
  <TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      includeInEntry: true,
      name: 'zod',
    },
  ],
};
```
  </TabItem>
</Tabs>

Or we can re-export only specific artifacts by providing a predicate function:

<Tabs>
  <TabItem label="example">
```ts title="index.ts"
export { zTag } from './zod.gen';
```
  </TabItem>
  <TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      includeInEntry: (symbol) => symbol.name === 'zTag',
      name: 'zod',
    },
  ],
};
```
  </TabItem>
</Tabs>

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript State Management (`web/src/content/docs/docs/openapi/typescript/state-management.mdx`)

---
title: State Management
description: Learn about handling state with @hey-api/openapi-ts.
sidebar:
  label: Overview
---

import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

# State Management

Any reasonably large application will have to deal with state management at some point. State-related code is often one of the biggest boilerplates in your codebase. Well, at least until you start using our state management plugins.

## Plugins

Hey API natively supports the following state managers.

- [Pinia Colada](/docs/openapi/typescript/plugins/pinia-colada)
- [TanStack Query](/docs/openapi/typescript/plugins/tanstack-query)
- [SWR](/docs/openapi/typescript/plugins/swr) <Badge text="Vote" variant="tip" />
- [Zustand](/docs/openapi/typescript/plugins/zustand) <Badge text="Vote" variant="tip" />

Don't see your state manager? Let us know by [opening an issue](https://github.com/hey-api/hey-api/issues).

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Validators (`web/src/content/docs/docs/openapi/typescript/validators.mdx`)

---
title: Validators
description: Learn about validating and transforming data with @hey-api/openapi-ts.
sidebar:
  label: Overview
---

import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

# Validators

There are times when you cannot blindly trust the server to return the correct data. You might be working on a critical application where any mistakes would be costly, or you're simply dealing with a legacy or undocumented system.

Validator plugins generate schemas from your input. You can connect them to your client as [validators](/docs/openapi/typescript/plugins/sdk#validators) or [transformers](/docs/openapi/typescript/plugins/sdk#transformers) via the SDK plugin.

## Features

- seamless integration with `@hey-api/openapi-ts` ecosystem
- schemas for requests, responses, and reusable definitions
- static type inference from schemas
- tree-shakeable output

## Plugins

Hey API natively supports the following validators.

- [Valibot](/docs/openapi/typescript/plugins/valibot)
- [Zod](/docs/openapi/typescript/plugins/zod)
- [Ajv](/docs/openapi/typescript/plugins/ajv) <Badge text="Vote" variant="tip" />
- [Arktype](/docs/openapi/typescript/plugins/arktype) <Badge text="Vote" variant="tip" />
- [Joi](/docs/openapi/typescript/plugins/joi) <Badge text="Vote" variant="tip" />
- [TypeBox](/docs/openapi/typescript/plugins/typebox) <Badge text="Vote" variant="tip" />
- [Yup](/docs/openapi/typescript/plugins/yup) <Badge text="Vote" variant="tip" />

Don't see your validator? Let us know by [opening an issue](https://github.com/hey-api/hey-api/issues).

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Web Frameworks (`web/src/content/docs/docs/openapi/typescript/web-frameworks.mdx`)

---
title: Web Frameworks
description: Learn about generating web framework code with @hey-api/openapi-ts.
sidebar:
  label: Overview
---

import { Badge } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

# Web Frameworks

There are two approaches to developing APIs: code-first, where you start with the code, or spec-first, where you begin with the specification. If you use the latter, you can ensure your APIs adhere to the specification with our web framework plugins.

## Plugins

Hey API natively supports the following frameworks.

- [Angular](/docs/openapi/typescript/plugins/angular)
- [Fastify](/docs/openapi/typescript/plugins/fastify)
- [Nest](/docs/openapi/typescript/plugins/nest)
- [oRPC](/docs/openapi/typescript/plugins/orpc)
- [Adonis](/docs/openapi/typescript/plugins/adonis) <Badge text="Vote" variant="tip" />
- [Elysia](/docs/openapi/typescript/plugins/elysia) <Badge text="Vote" variant="tip" />
- [Express](/docs/openapi/typescript/plugins/express) <Badge text="Vote" variant="tip" />
- [Hono](/docs/openapi/typescript/plugins/hono) <Badge text="Vote" variant="tip" />
- [Koa](/docs/openapi/typescript/plugins/koa) <Badge text="Vote" variant="tip" />
- [TanStack Start](/docs/openapi/typescript/plugins/tanstack-start) <Badge text="Vote" variant="tip" />

Don't see your framework? Let us know by [opening an issue](https://github.com/hey-api/hey-api/issues).

<Examples />

---

### Web Src Content Docs Docs Openapi Python Clients Aiohttp (`web/src/content/docs/docs/openapi/python/clients/aiohttp.mdx`)

---
title: AIOHTTP
description: AIOHTTP client for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# AIOHTTP

<FeatureStatus issueNumber={4098} status="planned" />

### About

[AIOHTTP](https://docs.aiohttp.org/) is an asynchronous HTTP client/server for asyncio and Python.

---

### Web Src Content Docs Docs Openapi Python Clients Custom (`web/src/content/docs/docs/openapi/python/clients/custom.mdx`)

---
title: Custom Client
description: Learn how to create your own Hey API client.
sidebar:
  label: Client
---

import Examples from '@/components/Examples.astro';

:::caution
Client API is in development. The interface might change before it becomes stable. We encourage you to leave feedback on [GitHub](https://github.com/hey-api/hey-api/issues/1213).
:::

You may need to write your own client if the available clients do not suit your needs or you're working on a proprietary use case. This can be easily achieved using the Client API. But don't take our word for it – all Hey API clients are written this way!

:::caution
Custom clients documentation will be finalized after further testing. Simplified [instructions](https://github.com/hey-api/hey-api/issues/1213#issuecomment-2765206344) can be found in the GitHub thread.
:::

<Examples />

---

### Web Src Content Docs Docs Openapi Python Clients Httpx (`web/src/content/docs/docs/openapi/python/clients/httpx.mdx`)

---
title: HTTPX Client
description: Generate a type-safe HTTPX client from OpenAPI with the HTTPX client for openapi-python. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: HTTPX
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
import UserConfig from '@/components/UserConfig.astro';

# HTTPX

### About

[HTTPX](https://www.python-httpx.org/) is a fully featured HTTP client for Python 3, which provides sync and async APIs, and support for both HTTP/1.1 and HTTP/2.

The HTTPX client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

{/* ### Demo

<StackBlitz
  example="hey-api-client-fetch-example"
  openFile={[
    'openapi-ts.config.ts',
    'src/client/schemas.gen.ts',
    'src/client/sdk.gen.ts',
    'src/client/types.gen.ts',
    'src/App.tsx',
  ]}
/> */}

## Features

- seamless integration with `@hey-api/openapi-python` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

In your [configuration](/docs/openapi/python/get-started), add `@hey-api/client-httpx` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-httpx'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-python \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-httpx
```
  </TabItem>
</Tabs>

:::note
This step is optional because HTTPX is the default client.
:::

## Configuration

The HTTPX client is built as a thin wrapper on top of HTTPX, extending its functionality to work with Hey API. If you're already familiar with HTTPX, configuring your client will feel like working directly with HTTPX.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/python/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any HTTPX configuration option to `setConfig()`, and even your own [HTTPX](#custom-instance) implementation.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseUrl: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-httpx',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseUrl: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. If needed, you can still use `setConfig()` to update the client configuration later.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseUrl: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseUrl: 'https://example.com', // <-- override default configuration
});
```

## Interceptors

Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.

They can be added with `use`, removed with `eject`, and updated wth `update`. The `use` and `update` methods will return the ID of the interceptor for use with `eject` and `update`. Fetch API does not have the interceptor functionality, so we implement our own.

### Example: Request interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(request) {
  // do something
  return request;
}

interceptorId = client.interceptors.request.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.request.eject(interceptorId);

// eject by reference
client.interceptors.request.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(request) {
  // do something
  return request;
}

// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

### Example: Response interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(response) {
  // do something
  return response;
}

interceptorId = client.interceptors.response.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.response.eject(interceptorId);

// eject by reference
client.interceptors.response.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(response) {
  // do something
  return response;
}

// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

:::tip
To eject, you must provide the ID or reference of the interceptor passed to `use()`, the ID is the value returned by `use()` and `update()`.
:::

## Auth

The SDKs include auth mechanisms for every endpoint. You will want to configure the `auth` field to pass the right token for each request. The `auth` field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  auth: () => '<my_token>',
  baseUrl: 'https://example.com',
});
```

If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.interceptors.request.use((request, options) => {
  request.headers.set('Authorization', 'Bearer <my_token>');
  return request;
});
```

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `fetch` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  fetch: () => {
    /* custom `fetch` method */
  },
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

<UserConfig package="openapi-python" plugin="@hey-api/client-httpx" />
<Examples />

---

### Web Src Content Docs Docs Openapi Python Clients Requests (`web/src/content/docs/docs/openapi/python/clients/requests.mdx`)

---
title: Requests
description: Requests client for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Requests

<FeatureStatus issueNumber={4097} status="planned" />

### About

[Requests](https://pypi.org/project/requests/) is a simple, yet elegant, HTTP library.

---

### Web Src Content Docs Docs Openapi Python Clients Urllib3 (`web/src/content/docs/docs/openapi/python/clients/urllib3.mdx`)

---
title: urllib3
description: urllib3 client for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# urllib3

<FeatureStatus issueNumber={4096} status="planned" />

### About

[urllib3](https://pypi.org/project/urllib3/) is a powerful, user-friendly HTTP client for Python. urllib3 brings many critical features that are missing from the Python standard libraries.

---

### Web Src Content Docs Docs Openapi Python Plugins Attrs (`web/src/content/docs/docs/openapi/python/plugins/attrs.mdx`)

---
title: Attrs
description: Attrs plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Attrs

<FeatureStatus issueNumber={4095} status="planned" />

### About

[Attrs](https://www.attrs.org/) is the Python package that will bring back the joy of writing classes by relieving you from the drudgery of implementing object protocols (aka dunder methods). Trusted by NASA for Mars missions since 2020!

---

### Web Src Content Docs Docs Openapi Python Plugins Custom (`web/src/content/docs/docs/openapi/python/plugins/custom.mdx`)

---
title: Custom Plugin
description: Learn how to create your own Hey API plugin.
sidebar:
  label: Plugin
---

import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

:::caution
Plugin API is in development. The interface might change before it becomes stable. We encourage you to leave feedback on [GitHub](https://github.com/hey-api/hey-api/issues).
:::

You may need to write your own plugin if the available plugins do not suit your needs or you're working on a proprietary use case. This can be easily achieved using the Plugin API. But don't take our word for it – all Hey API plugins are written this way!

## File Structure

We recommend following the design pattern of the native plugins. You can browse the code on [GitHub](https://github.com/hey-api/hey-api/tree/main/packages/openapi-ts/src/plugins) as you follow this tutorial.

<FileTree>
- my-plugin/
  - config.ts
  - imports.ts
  - index.ts
  - plugin.ts
  - types.ts
</FileTree>

First, create a `my-plugin` folder for your plugin files. Inside, create a barrel file `index.ts` exporting the plugin.

```ts title="index.ts"
export { defaultConfig, defineConfig } from './config';
export type { MyPlugin } from './types';
```

## Types

`index.ts` references two files, so we need to create them. `types.ts` contains the TypeScript interface for your plugin options.

```ts title="types.ts"
import type { DefinePlugin, Plugin } from '@hey-api/openapi-ts';

export type UserConfig = Plugin.Name<'my-plugin'> &
  Plugin.Hooks &
  Plugin.UserExports & {
    /**
     * User-configurable option for your plugin.
     */
    user?: number | string | {
      age?: number;
      name?: string;
    };
  };

export type Config = Plugin.Name<'my-plugin'> &
  Plugin.Hooks &
  Plugin.Exports & {
    /** Resolved option for your plugin. */
    user: {
      age: number;
      name: string;
    };
  };

export type MyPlugin = DefinePlugin<UserConfig, Config>;
```

- `Plugin.Name` sets the plugin's unique identifier.
- `Plugin.Hooks` allows users to override plugin behavior through event hooks. For example, users can control how schemas are extracted or how symbols are routed to files.
- `Plugin.Exports` add the `includeInEntry` option, which controls whether your plugin's exports are re-exported from the output entry file.
- `UserConfig` is what users write in their config file. `Config` is the fully resolved shape your handler receives.

## Configuration

`config.ts` defines the runtime configuration for your plugin, including how user input is resolved into `Config` and the `handler` function that generates output.

```ts title="config.ts"
import { definePluginConfig } from '@hey-api/openapi-ts';

import { handler } from './plugin';
import type { MyPlugin } from './types';

export const defaultConfig: MyPlugin['Config'] = {
  config: {
    user: {
      age: 42,
      name: 'Stan Smith',
    },
  },
  handler,
  name: 'my-plugin',
};

/**
 * Type helper for `my-plugin` plugin, returns {@link Plugin.Config} object
 */
export const defineConfig = definePluginConfig(defaultConfig);
```

The `config` table is a declarative resolution spec. Each field declares its default value and optional coercion rules. To allow users to set either `age` or `name` through the `user` field, we can add coercion rules to transform primitive values into the expected shape.

<Tabs>
  <TabItem label="config">
```ts {9-12} title="config.ts"
import { definePluginConfig } from '@hey-api/openapi-ts';

import { handler } from './plugin';
import type { MyPlugin } from './types';

export const defaultConfig: MyPlugin['Config'] = {
  config: {
    user: {
      $coerce: {
        number: (v) => ({ age: v }),
        string: (v) => ({ name: v }),
      },
      age: 42,
      name: 'Stan Smith',
    },
  },
  handler,
  name: 'my-plugin',
};

/**
 * Type helper for `my-plugin` plugin, returns {@link Plugin.Config} object
 */
export const defineConfig = definePluginConfig(defaultConfig);
```
  </TabItem>
  <TabItem label="input">
```js {8} title="openapi-ts.config.ts"
import { defineConfig } from 'path/to/my-plugin';

export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    defineConfig({
      user: 'Joe Doe', // or number to set age
    }),
  ],
};
```
  </TabItem>
  <TabItem label="resolved">
```ts
{
  user: {
    age: 42,
    name: 'Joe Doe'
  }
}
```
  </TabItem>
</Tabs>

### Dependencies

Plugins can declare dependencies on other plugins. A dependency will always be included in the output, even if the user hasn't explicitly added it to their `plugins` config. This is useful when your plugin's output builds on another plugin's types or symbols.

```ts {3} title="config.ts"
export const defaultConfig: MyPlugin['Config'] = {
  config: { ... },
  dependencies: ['@hey-api/typescript'],
  handler,
  name: 'my-plugin',
};
```

#### Resolving tags

Some dependencies aren't known at authoring time, such as which validator plugin the user has installed. Use `resolveTag` inside a `coerce()` call to look up the active plugin for a given tag at resolution time. In most cases, you'll also want to declare a dependency on the field to ensure it's included in the output.

```ts {1,2,6,9} title="config.ts"
import type { PluginContext } from '@hey-api/openapi-ts';
import { coerce } from '@hey-api/openapi-ts';

export const defaultConfig: MyPlugin['Config'] = {
  config: {
    $dependencies: ['validator'],
    validator: coerce((value, context) => {
      if (value === true || value === undefined) {
        return (context as PluginContext).resolveTag('validator');
      }
      return value;
    }),
  },
  dependencies: ['@hey-api/typescript'],
  handler,
  name: 'my-plugin',
};
```

## Handler

The `handler` function generates the actual output. We recommend implementing it in `plugin.ts`.

```ts title="plugin.ts"
import { $ } from '@hey-api/openapi-ts';

import type { MyPlugin } from './types';

export const handler: MyPlugin['Handler'] = ({ plugin }) => {
  plugin.forEach('operation', 'schema', (event) => {
    if (event.type === 'operation') {
      // do something with the operation
    } else if (event.type === 'schema') {
      // do something with the schema
    }
  });

  // use the TypeScript DSL to build nodes
  const symbolName = plugin.symbol('user');
  const node = $.const(symbolName)
    .export()
    .assign($.literal(plugin.config.user.name));
  plugin.node(node);
};
```

## Imports

Imports are a type-safe way to reference external symbols your plugin works with. Rather than querying or constructing identifiers manually, you declare them once and access them through `plugin.imports` anywhere in your handler.

Imports are also visible to users customizing your plugin's behavior. When a user provides hooks like `$resolvers`, they receive the `plugin` instance and can access `plugin.imports` to reference your plugin's imports directly.

<Tabs>
  <TabItem label="imports">
```ts title="imports.ts"
import type { PluginInstance } from '@hey-api/openapi-ts';

export function myPluginImports(plugin: PluginInstance) {
  const factory = plugin.symbolFactory;
  return {
    myLib: factory.register('myLib', { external: 'my-lib' }),
  };
}

export type MyPluginImports = ReturnType<typeof myPluginImports>;
```
  </TabItem>
  <TabItem label="types">
```ts {1,5} title="types.ts"
import type { MyPluginImports } from './imports';

/** ... */

export type MyPlugin = DefinePlugin<UserConfig, Config, never, MyPluginImports>;
```
  </TabItem>
  <TabItem label="config">
```ts {1,6} title="config.ts"
import { myPluginImports } from './imports';

export const defaultConfig: MyPlugin['Config'] = {
  config: { ... },
  handler,
  imports: myPluginImports,
  name: 'my-plugin',
};
```
  </TabItem>
  <TabItem label="handler">
```ts {2} title="plugin.ts"
export const handler: MyPlugin['Handler'] = ({ plugin }) => {
  const { myLib } = plugin.imports;
  // use myLib as a typed reference when building nodes
};
```
  </TabItem>
</Tabs>

## Usage

Once you're satisfied with your plugin, register it in the [configuration](/docs/openapi/typescript/configuration) file.

```js {1,7} title="openapi-ts.config.ts"
import { defineConfig } from 'path/to/my-plugin';

export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    defineConfig(),
  ],
};
```

## Output

Putting all of this together will generate the following `my-plugin.gen.ts` file.

```ts title="my-plugin.gen.ts"
export const user = 'Stan Smith';
```

Congratulations! You've successfully created your own plugin! 🎉

<Examples />

---

### Web Src Content Docs Docs Openapi Python Plugins Dataclasses (`web/src/content/docs/docs/openapi/python/plugins/dataclasses.mdx`)

---
title: Dataclasses
description: Dataclasses plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Dataclasses

<FeatureStatus issueNumber={4094} status="planned" />

### About

[Dataclasses](https://docs.python.org/3/library/dataclasses.html) is a module that provides a decorator and functions for automatically adding generated special methods such as `__init__()` and `__repr__()` to user-defined classes.

---

### Web Src Content Docs Docs Openapi Python Plugins Factory Boy (`web/src/content/docs/docs/openapi/python/plugins/factory-boy.mdx`)

---
title: Factory Boy
description: Factory Boy plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Factory Boy

<FeatureStatus issueNumber={4093} status="planned" />

### About

[Factory Boy](https://factoryboy.readthedocs.io/) is a fixtures replacement based on thoughtbot's factory_bot. As a fixtures replacement tool, it aims to replace static, hard to maintain fixtures with easy-to-use factories for complex objects.

---

### Web Src Content Docs Docs Openapi Python Plugins Faker (`web/src/content/docs/docs/openapi/python/plugins/faker.mdx`)

---
title: Faker
description: Faker plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Faker

<FeatureStatus issueNumber={4092} status="planned" />

### About

[Faker](https://pypi.org/project/Faker/) is a Python package that generates fake data for you. Whether you need to bootstrap your database, create good-looking XML documents, fill-in your persistence to stress test it, or anonymize data taken from a production service, Faker is for you.

---

### Web Src Content Docs Docs Openapi Python Plugins Marshmallow (`web/src/content/docs/docs/openapi/python/plugins/marshmallow.mdx`)

---
title: Marshmallow
description: Marshmallow plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Marshmallow

<FeatureStatus issueNumber={4091} status="planned" />

### About

[Marshmallow](https://marshmallow.readthedocs.io/) is an ORM/ODM/framework-agnostic library for converting complex datatypes, such as objects, to and from native Python datatypes.

---

### Web Src Content Docs Docs Openapi Python Plugins Mimesis (`web/src/content/docs/docs/openapi/python/plugins/mimesis.mdx`)

---
title: Mimesis
description: Mimesis plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Mimesis

<FeatureStatus issueNumber={4090} status="planned" />

### About

[Mimesis](https://mimesis.name/) is a powerful data generator for Python that can produce a wide range of fake data in multiple languages.

---

### Web Src Content Docs Docs Openapi Python Plugins Pydantic (`web/src/content/docs/docs/openapi/python/plugins/pydantic.mdx`)

---
title: Pydantic v2 Plugin
description: Generate Pydantic v2 models from OpenAPI with the Pydantic plugin for openapi-python. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Pydantic
custom:
  version: v2
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# Pydantic

### About

[Pydantic](https://pydantic.dev/docs/validation/latest/get-started/) is the most widely used data validation library for Python. Fast and extensible, Pydantic plays nicely with your linters/IDE/brain.

The Pydantic plugin for Hey API generates models from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

## Features

- Pydantic v2 support
- seamless integration with `@hey-api/openapi-python` ecosystem
- Pydantic models for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/python/get-started), add `pydantic` to your plugins and you'll be ready to generate Pydantic artifacts. 🎉

```js {6} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'pydantic',
  ],
};
```

### SDKs

Pydantic can validate or transform data directly in your SDK. Set `validator` or `transformer` to `true` on the SDK plugin to enable it.

<Tabs>
  <TabItem label="validator">
```js {7-10} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'pydantic',
    {
      name: '@hey-api/sdk',
      validator: true,
    },
  ],
};
```
  </TabItem>
  <TabItem label="transformer">
```js {7-10} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'pydantic',
    {
      name: '@hey-api/sdk',
      transformer: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

The SDK page covers [validators](/docs/openapi/python/plugins/sdk#validators) and [transformers](/docs/openapi/python/plugins/sdk#transformers) in more detail.

## Output

The Pydantic plugin will generate the following artifacts, depending on the input specification.

## Requests

A Pydantic model is generated for every request layer of each endpoint.

<Tabs>
  <TabItem label="example">
```ts title="pydantic.gen.ts"
const vDeletePetHeaders = v.object({
  api_key: v.optional(v.string()),
});

const vDeletePetPath = v.object({
  petId: v.number(),
});

const vDeletePetQuery = v.object({
  additionalMetadata: v.string(),
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'pydantic',
      requests: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `requests` schemas using the `.name` and `.case` options.

## Responses

A single Pydantic model is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated model is a union of all possible response shapes.

<Tabs>
  <TabItem label="example">
```ts title="pydantic.gen.ts"
const vResponse = v.union([
  v.object({
    foo: v.optional(v.string()),
  }),
  v.object({
    bar: v.optional(v.number()),
  }),
]);
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'pydantic',
      responses: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `responses` schemas using the `.name` and `.case` options.

## Definitions

A Pydantic model is generated for every reusable definition from your input.

<Tabs>
  <TabItem label="example">
```ts title="pydantic.gen.ts"
const vFoo = v.pipe(v.number(), v.integer());

const vBar = v.object({
  bar: v.optional(v.array(v.pipe(v.number(), v.integer()))),
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'pydantic',
      definitions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `definitions` schemas using the `.name` and `.case` options.

## Metadata

It's often useful to associate a schema with some additional [metadata](https://pydantic-docs.helpmanual.io/usage/schema/#metadata) for documentation, code generation, AI structured outputs, form validation, and other purposes. You can set `metadata` to `true` to attach descriptions to schemas when available.

<Tabs>
  <TabItem label="example">
```ts title="pydantic.gen.ts"
export const vFoo = v.pipe(
  v.string(),
  v.metadata({
    description: 'Additional metadata',
  }),
);
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'pydantic',
      metadata: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

For more control over metadata, you can provide your own function. It receives the source `schema`, the target `node` object, and the `$` builder for populating metadata.

<Tabs>
  <TabItem label="example">
```ts title="pydantic.gen.ts"
export const vFoo = v.pipe(
  v.string(),
  v.metadata({
    hasTitle: false,
    createdAt: 1735732800000,
  }),
);
```
  </TabItem>
  <TabItem label="config">
```js {8-11} title="openapi-python.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'pydantic',
      metadata({ $, node, schema }) {
        node.prop('hasTitle', $.literal(Boolean(schema.title)));
        node.prop('createdAt', $.literal(Date.now()));
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Resolvers

You can further customize this plugin's behavior using [resolvers](/docs/openapi/python/plugins/concepts/resolvers).

<UserConfig package="openapi-python" plugin="pydantic" />
{/* <Examples /> */}

---

### Web Src Content Docs Docs Openapi Typescript Clients Axios (`web/src/content/docs/docs/openapi/typescript/clients/axios.mdx`)

---
title: Axios v1 Client
description: Generate a type-safe Axios v1 client from OpenAPI with the Axios client for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Axios
custom:
  version: v1
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
import UserConfig from '@/components/UserConfig.astro';

# Axios

### About

[Axios](https://axios-http.com) is a simple promise based HTTP client for the browser and Node.js. Axios provides a simple to use library in a small package with a very extensible interface.

The Axios client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

### Demo

<StackBlitz
  example="hey-api-client-axios-example"
  openFile={[
    'openapi-ts.config.ts',
    'src/client/schemas.gen.ts',
    'src/client/sdk.gen.ts',
    'src/client/types.gen.ts',
    'src/App.tsx',
  ]}
/>

## Features

- Axios v1 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/client-axios` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-axios'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-ts \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-axios
```
  </TabItem>
</Tabs>

## Configuration

The Axios client is built as a thin wrapper on top of Axios, extending its functionality to work with Hey API. If you're already familiar with Axios, configuring your client will feel like working directly with Axios.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/typescript/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any Axios configuration option to `setConfig()` (except for `auth`), and even your own [Axios](#custom-instance) implementation.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseURL: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-axios',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseURL: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. If needed, you can still use `setConfig()` to update the client configuration later.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseURL: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseURL: 'https://example.com', // <-- override default configuration
});
```

## Interceptors

Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application. Axios provides interceptors, please refer to their documentation on [interceptors](https://axios-http.com/docs/interceptors).

We expose the Axios instance through the `instance` field.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.instance.interceptors.request.use((config) => {
  // do something
  return config;
});
```

## Auth

The SDKs include auth mechanisms for every endpoint. You will want to configure the `auth` field to pass the right token for each request. The `auth` field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  auth: () => '<my_token>',
  baseURL: 'https://example.com',
});
```

If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.instance.interceptors.request.use((config) => {
  config.headers.set('Authorization', 'Bearer <my_token>');
  return config;
});
```

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `axios` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import axios from 'axios';
import { client } from 'client/client.gen';

// Customize the default axios instance
axios.defaults.baseURL = 'https://example.com';

client.setConfig({
  axios: axios,
});
```

or you can pass an `AxiosInstance` created with `axios.create()`:

```js title="src/index.ts"
import axios from 'axios';
import { client } from 'client/client.gen';

const customAxiosInstance = axios.create({
  baseURL: 'https://example.com',
});

client.setConfig({
  axios: customAxiosInstance,
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

<UserConfig package="openapi-ts" plugin="@hey-api/client-axios" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Clients Custom (`web/src/content/docs/docs/openapi/typescript/clients/custom.mdx`)

---
title: Custom Client
description: Learn how to create your own Hey API client.
sidebar:
  label: Client
---

import Examples from '@/components/Examples.astro';

:::caution
Client API is in development. The interface might change before it becomes stable. We encourage you to leave feedback on [GitHub](https://github.com/hey-api/hey-api/issues/1213).
:::

You may need to write your own client if the available clients do not suit your needs or you're working on a proprietary use case. This can be easily achieved using the Client API. But don't take our word for it – all Hey API clients are written this way!

:::caution
Custom clients documentation will be finalized after further testing. Simplified [instructions](https://github.com/hey-api/hey-api/issues/1213#issuecomment-2765206344) can be found in the GitHub thread.
:::

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Clients Effect (`web/src/content/docs/docs/openapi/typescript/clients/effect.mdx`)

---
title: Effect client
description: Effect client for Hey API. Compatible with all our features.
sidebar:
  label: Effect
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Effect

<FeatureStatus issueNumber={2082} status="planned" />

### About

[Effect](https://effect.website/) is a powerful TypeScript library designed to help developers easily create complex, synchronous, and asynchronous programs.

---

### Web Src Content Docs Docs Openapi Typescript Clients Fetch (`web/src/content/docs/docs/openapi/typescript/clients/fetch.mdx`)

---
title: Fetch API Client
description: Generate a type-safe Fetch API client from OpenAPI with the Fetch API client for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Fetch API
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
import UserConfig from '@/components/UserConfig.astro';

# Fetch API

### About

The [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API) provides an interface for fetching resources (including across the network). It is a more powerful and flexible replacement for XMLHttpRequest.

The Fetch API client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

### Demo

<StackBlitz
  example="hey-api-client-fetch-example"
  openFile={[
    'openapi-ts.config.ts',
    'src/client/schemas.gen.ts',
    'src/client/sdk.gen.ts',
    'src/client/types.gen.ts',
    'src/App.tsx',
  ]}
/>

## Features

- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/client-fetch` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-fetch'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-ts \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-fetch
```
  </TabItem>
</Tabs>

:::note
This step is optional because Fetch is the default client.
:::

## Configuration

The Fetch client is built as a thin wrapper on top of Fetch API, extending its functionality to work with Hey API. If you're already familiar with Fetch, configuring your client will feel like working directly with Fetch API.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/typescript/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any Fetch API configuration option to `setConfig()`, and even your own [Fetch](#custom-instance) implementation.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseUrl: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-fetch',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseUrl: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. If needed, you can still use `setConfig()` to update the client configuration later.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseUrl: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseUrl: 'https://example.com', // <-- override default configuration
});
```

## Interceptors

Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.

They can be added with `use`, removed with `eject`, and updated wth `update`. The `use` and `update` methods will return the ID of the interceptor for use with `eject` and `update`. Fetch API does not have the interceptor functionality, so we implement our own.

### Example: Request interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(request) {
  // do something
  return request;
}

interceptorId = client.interceptors.request.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.request.eject(interceptorId);

// eject by reference
client.interceptors.request.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(request) {
  // do something
  return request;
}

// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

### Example: Response interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(response) {
  // do something
  return response;
}

interceptorId = client.interceptors.response.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.response.eject(interceptorId);

// eject by reference
client.interceptors.response.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(response) {
  // do something
  return response;
}

// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

:::tip
To eject, you must provide the ID or reference of the interceptor passed to `use()`, the ID is the value returned by `use()` and `update()`.
:::

## Auth

The SDKs include auth mechanisms for every endpoint. You will want to configure the `auth` field to pass the right token for each request. The `auth` field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  auth: () => '<my_token>',
  baseUrl: 'https://example.com',
});
```

If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.interceptors.request.use((request, options) => {
  request.headers.set('Authorization', 'Bearer <my_token>');
  return request;
});
```

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `fetch` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  fetch: () => {
    /* custom `fetch` method */
  },
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

<UserConfig package="openapi-ts" plugin="@hey-api/client-fetch" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Clients Got (`web/src/content/docs/docs/openapi/typescript/clients/got.mdx`)

---
title: Got client
description: Got client for Hey API. Compatible with all our features.
sidebar:
  label: Got
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Got

<FeatureStatus issueNumber={586} status="planned" />

### About

[Got](https://github.com/sindresorhus/got) is a human-friendly and powerful HTTP request library for Node.js.

---

### Web Src Content Docs Docs Openapi Typescript Clients Ky (`web/src/content/docs/docs/openapi/typescript/clients/ky.mdx`)

---
title: Ky v1 Client
description: Generate a type-safe Ky v1 client from OpenAPI with the Ky client for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Ky
custom:
  version: v1
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
import { sebastiaanWouters } from '@/data/people';

# Ky

### About

[Ky](https://github.com/sindresorhus/ky) is a tiny and elegant JavaScript HTTP client based on the Fetch API.

The Ky client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

### Collaborators

<AuthorsList people={[sebastiaanWouters]} />

## Features

- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/client-ky` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-ky'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-ts \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-ky
```
  </TabItem>
</Tabs>

## Configuration

The Ky client is built as a thin wrapper on top of Ky, extending its functionality to work with Hey API. If you're already familiar with Ky, configuring your client will feel like working directly with Ky.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/typescript/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any Ky configuration option to `setConfig()`, and even your own [`ky`](#custom-instance) instance.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseUrl: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-ky',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseUrl: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. If needed, you can still use `setConfig()` to update the client configuration later.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseUrl: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseUrl: 'https://example.com', // <-- override default configuration
});
```

## Interceptors

Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.

They can be added with `use`, removed with `eject`, and updated wth `update`. The `use` and `update` methods will return the ID of the interceptor for use with `eject` and `update`. Ky does not have the interceptor functionality, so we implement our own.

### Example: Request interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(request) {
  // do something
  return request;
}

interceptorId = client.interceptors.request.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.request.eject(interceptorId);

// eject by reference
client.interceptors.request.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(request) {
  // do something
  return request;
}

// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

### Example: Response interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(response) {
  // do something
  return response;
}

interceptorId = client.interceptors.response.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.response.eject(interceptorId);

// eject by reference
client.interceptors.response.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(response) {
  // do something
  return response;
}

// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

:::tip
To eject, you must provide the ID or reference of the interceptor passed to `use()`, the ID is the value returned by `use()` and `update()`.
:::

## Auth

The SDKs include auth mechanisms for every endpoint. You will want to configure the `auth` field to pass the right token for each request. The `auth` field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  auth: () => '<my_token>',
  baseUrl: 'https://example.com',
});
```

If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.interceptors.request.use((request, options) => {
  request.headers.set('Authorization', 'Bearer <my_token>');
  return request;
});
```

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `ky` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  ky: ky.create({
    /* custom `ky` instance */
  }),
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

<UserConfig package="openapi-ts" plugin="@hey-api/client-ky" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Clients Next Js (`web/src/content/docs/docs/openapi/typescript/clients/next-js.mdx`)

---
title: Next.js Client
description: Generate a type-safe Next.js client from OpenAPI with the Next.js client for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Next.js
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# Next.js

### About

[Next.js](https://nextjs.org) is the React framework for the web. Used by some of the world's largest companies, Next.js enables you to create high-quality web applications with the power of React components.

The Next.js client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

## Features

- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/client-next` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-next'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-ts \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-next
```
  </TabItem>
</Tabs>

## Configuration

The Next.js client is built as a thin wrapper on top of [fetch](https://nextjs.org/docs/app/api-reference/functions/fetch), extending its functionality to work with Hey API. If you're already familiar with Fetch, configuring your client will feel like working directly with Fetch API.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/typescript/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-next',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseUrl: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. This is the recommended approach because it guarantees the client will be initialized in both server and client environment. If needed, you can still use `setConfig()` to update the client configuration later.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any Fetch API configuration option to `setConfig()`, and even your own [Fetch](#custom-instance) implementation.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseUrl: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, this might be an acceptable trade-off. However, our Next.js users usually want to use the first approach.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseUrl: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseUrl: 'https://example.com', // <-- override default configuration
});
```

## Interceptors

Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.

They can be added with `use`, removed with `eject`, and updated wth `update`. The `use` and `update` methods will return the ID of the interceptor for use with `eject` and `update`. Fetch API does not have the interceptor functionality, so we implement our own.

### Example: Request interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(request) {
  // do something
  return request;
}

interceptorId = client.interceptors.request.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.request.eject(interceptorId);

// eject by reference
client.interceptors.request.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(request) {
  // do something
  return request;
}

// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

### Example: Response interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(response) {
  // do something
  return response;
}

interceptorId = client.interceptors.response.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.response.eject(interceptorId);

// eject by reference
client.interceptors.response.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(response) {
  // do something
  return response;
}

// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

:::tip
To eject, you must provide the ID or reference of the interceptor passed to `use()`, the ID is the value returned by `use()` and `update()`.
:::

## Auth

The SDKs include auth mechanisms for every endpoint. You will want to configure the `auth` field to pass the right token for each request. The `auth` field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  auth: () => '<my_token>',
  baseUrl: 'https://example.com',
});
```

If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.interceptors.request.use((options) => {
  options.headers.set('Authorization', 'Bearer <my_token>');
});
```

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `fetch` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  fetch: () => {
    /* custom `fetch` method */
  },
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

<UserConfig package="openapi-ts" plugin="@hey-api/client-next" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Clients Nuxt (`web/src/content/docs/docs/openapi/typescript/clients/nuxt.mdx`)

---
title: Nuxt v3 Client
description: Generate a type-safe Nuxt v3 client from OpenAPI with the Nuxt client for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Nuxt
custom:
  version: v3
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import InstallCommand from '@/components/package-managers/InstallCommand.astro';
import UserConfig from '@/components/UserConfig.astro';

# Nuxt

<FeatureStatus status="beta" />

### About

[Nuxt](https://nuxt.com) is an open source framework that makes web development intuitive and powerful.

The Nuxt client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

## Features

- Nuxt v3 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

Start by adding `@hey-api/nuxt` to your dependencies.

<InstallCommand packageName="@hey-api/nuxt" exactVersion={false} isDevDependency={false} />

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/client-nuxt` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-nuxt'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-ts \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-nuxt
```
  </TabItem>
</Tabs>

:::tip
If you add `@hey-api/nuxt` to your Nuxt modules, this step is not needed.
:::

## Configuration

The Nuxt client is built as a thin wrapper on top of Nuxt, extending its functionality to work with Hey API. If you're already familiar with Nuxt, configuring your client will feel like working directly with Nuxt.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/typescript/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any Nuxt configuration option to `setConfig()`, and even your own [`$fetch`](#custom-instance) implementation.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseURL: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-nuxt',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseURL: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. If needed, you can still use `setConfig()` to update the client configuration later.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseURL: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseURL: 'https://example.com', // <-- override default configuration
});
```

## Interceptors

Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application. Nuxt provides interceptors through ofetch, please refer to their documentation on [$fetch](https://nuxt.com/docs/api/utils/dollarfetch).

You can pass any Nuxt/ofetch arguments to the client instance.

:::note
If you omit `composable`, `$fetch` is used by default.
:::

```js title="src/index.ts"
import { client } from 'client/client.gen';

const result = await client.get({
  composable: '$fetch',
  onRequest: (context) => {
    // do something
  },
  url: '/foo',
});
```

## Auth

The SDKs include auth mechanisms for every endpoint. You will want to configure the `auth` field to pass the right token for each request. The `auth` field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  auth: () => '<my_token>',
  baseURL: 'https://example.com',
});
```

If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.

```js {5} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  onRequest: ({ options }) => {
    options.headers.set('Authorization', 'Bearer <my_token>');
  },
});
```

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `$fetch` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  $fetch: () => {
    /* custom `$fetch` method */
  },
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

<UserConfig package="openapi-ts" plugin="@hey-api/client-nuxt" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Clients Ofetch (`web/src/content/docs/docs/openapi/typescript/clients/ofetch.mdx`)

---
title: OFetch Client
description: Generate a type-safe ofetch client from OpenAPI with the ofetch client for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: OFetch
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
import { dmitriyBrolnickij } from '@/data/people';

# OFetch

### About

[`ofetch`](https://github.com/unjs/ofetch) is a better Fetch API that adds useful defaults and features such as automatic response parsing, request/response hooks, and it works in Node, browser, and workers.

The `ofetch` client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

### Collaborators

<AuthorsList people={[dmitriyBrolnickij]} />

## Features

- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/client-ofetch` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-ofetch'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-ts \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-ofetch
```
  </TabItem>
</Tabs>

## Configuration

The `ofetch` client is built as a thin wrapper on top of `ofetch`, extending its functionality to work with Hey API. If you're already familiar with `ofetch`, configuring your client will feel like working directly with `ofetch`.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/typescript/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any `ofetch` configuration option to `setConfig()`, and even your own [`ofetch`](#custom-instance) instance.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseUrl: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-ofetch',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseUrl: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. If needed, you can still use `setConfig()` to update the client configuration later.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseUrl: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseUrl: 'https://example.com', // <-- override default configuration
});
```

## Interceptors

Interceptors (middleware) can be used to modify requests before they're sent or responses before they're returned to your application.

The `ofetch` client supports two complementary options:

- built-in Hey API interceptors exposed via `client.interceptors`
- native `ofetch` hooks passed through config (e.g., `onRequest`)

### Example: Request interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(request) {
  // do something
  return request;
}

interceptorId = client.interceptors.request.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.request.eject(interceptorId);

// eject by reference
client.interceptors.request.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(request) {
  // do something
  return request;
}

// update by ID
client.interceptors.request.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.request.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

### Example: Response interceptor

<Tabs>
  <TabItem label="use">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myInterceptor(response) {
  // do something
  return response;
}

interceptorId = client.interceptors.response.use(myInterceptor);
```
  </TabItem>
  <TabItem label="eject">
```js title="src/index.ts"
import { client } from 'client/client.gen';

// eject by ID
client.interceptors.response.eject(interceptorId);

// eject by reference
client.interceptors.response.eject(myInterceptor);
```
  </TabItem>
  <TabItem label="update">
```js title="src/index.ts"
import { client } from 'client/client.gen';

async function myNewInterceptor(response) {
  // do something
  return response;
}

// update by ID
client.interceptors.response.update(interceptorId, myNewInterceptor);

// update by reference
client.interceptors.response.update(myInterceptor, myNewInterceptor);
```
  </TabItem>
</Tabs>

:::tip
To eject, you must provide the ID or reference of the interceptor passed to `use()`, the ID is the value returned by `use()` and `update()`.
:::

### Example: `ofetch` hooks

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  onRequest: ({ options }) => {
    // mutate ofetch options (headers, query, etc.)
  },
  onResponse: ({ response }) => {
    // inspect/transform the raw Response
  },
  onRequestError: (ctx) => {
    // handle request errors
  },
  onResponseError: (ctx) => {
    // handle response errors
  },
});
```

## Auth

The SDKs include auth mechanisms for every endpoint. You will want to configure the `auth` field to pass the right token for each request. The `auth` field can be a string or a function returning a string representing the token. The returned value will be attached only to requests that require auth.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  auth: () => '<my_token>',
  baseUrl: 'https://example.com',
});
```

If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.

```js {4} title="src/index.ts"
import { client } from 'client/client.gen';

client.interceptors.request.use((request, options) => {
  request.headers.set('Authorization', 'Bearer <my_token>');
  return request;
});
```

You can also use the `ofetch` hooks.

```js {5} title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  onRequest: ({ options }) => {
    options.headers.set('Authorization', 'Bearer <my_token>');
  },
});
```

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `ofetch` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import { ofetch } from 'ofetch';
import { client } from 'client/client.gen';

const customOFetchInstance = ofetch.create({
  onRequest: ({ options }) => {
    // customize request
  },
  onResponse: ({ response }) => {
    // customize response
  },
});

client.setConfig({
  ofetch: customOFetchInstance,
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

<UserConfig package="openapi-ts" plugin="@hey-api/client-ofetch" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Community Contributing (`web/src/content/docs/docs/openapi/typescript/community/contributing.mdx`)

---
title: Contributing
description: Learn how to contribute to Hey API.
sidebar:
  label: Overview
---

# Contributor Manual

## Foreword

Hey API is an ecosystem for turning API specifications into production-ready code. It's trusted by thousands of companies – from YC startups to Fortune 500 enterprises – and powers products used by millions worldwide.

We welcome contributors of all backgrounds and experience levels. Whether you're fixing a typo or building a new feature, your input matters. If you need guidance, help with technical writing, or want to bring a feature idea to life, we're here to support you.

:::tip
New to open source? Take a look at the [Open Source](https://opensource.guide/) or [First Contributions](https://github.com/firstcontributions/first-contributions) guides for helpful information on contributing to open source projects.
:::

## First Steps

There are many ways to contribute to Hey API. Most of them don't involve writing any code!

- **Read the documentation**. Start with the [Get Started](/docs/openapi/typescript/get-started) guide. If you find anything broken or confusing, you can suggest improvements by clicking "Edit" at the bottom of any page.

- **Browse open issues**. Help others by providing workarounds, asking for clarification, triaging, or suggesting labels on [open issues](https://github.com/hey-api/hey-api/issues). If you see something you would like to work on, consider opening a pull request.

- **Participate in discussions**. Ask or [answer questions](https://github.com/orgs/hey-api/discussions), provide feedback, or suggest new ideas. Every idea is welcome, no matter how big or small.

- **Engage on social media**. Help others discover Hey API by engaging with our posts on [LinkedIn](https://linkedin.com/company/heyapi), [Bluesky](https://bsky.app/profile/heyapi.dev), or [X](https://x.com/mrlubos). Share your experiences with Hey API on Reddit, Slack, or in your own communities and group chats.

- **Create a new issue**. If you can't find a solution, [open an issue](https://github.com/hey-api/hey-api/issues). The issue template will guide you through the process.

- **Open a pull request**. If you find an issue you would like to fix, open a pull request. If you need help, tag [`@mrlubos`](https://github.com/mrlubos) on GitHub, provide enough relevant information, and we will do our best to assist you.

These are some of the best ways not only to contribute to Hey API, but also to learn, connect with others, and share ideas.

## Pull Requests

Ready to write some code? We have dedicated guides to help you [build](/docs/openapi/typescript/community/contributing/building), [develop](/docs/openapi/typescript/community/contributing/developing), and [test](/docs/openapi/typescript/community/contributing/testing) your feature before it's released.

We are excited to see what you'll contribute!

---

### Web Src Content Docs Docs Openapi Typescript Community Spotlight (`web/src/content/docs/docs/openapi/typescript/community/spotlight.mdx`)

---
title: Spotlight
description: Meet the people behind Hey API.
---

import { coreTeam, hallOfFame } from '@/data/people';
import Contributors from '@/components/Contributors.astro';
import TeamMembers from '@/components/TeamMembers.astro';

# Spotlight

Meet the people behind Hey API. To join this list, please refer to the [contributing](/docs/openapi/typescript/community/contributing) guide.

## Core Team

These people actively maintain Hey API.

<TeamMembers members={coreTeam} />

Do you want to join the core team? Send us a short [email](mailto:lubos@heyapi.dev?subject=Join%20Core%20Team) describing your interest in Hey API, any relevant experience, and what you're hoping to work on.

## Hall of Fame

These are the people with significant contributions to Hey API. A special thank you goes to [Ferdi Koomen](https://madebyferdi.com) for allowing us to use the original source code from OpenAPI TypeScript Codegen. None of this would've been possible without you!

<TeamMembers members={hallOfFame} />

## Contributors

The complete list of contributors to Hey API.

<Contributors />

A sincere thank you for your contributions.

---

### Web Src Content Docs Docs Openapi Typescript Configuration Input (`web/src/content/docs/docs/openapi/typescript/configuration/input.mdx`)

---
title: Input
description: Configure @hey-api/openapi-ts.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import InputTabs from '@/components/code-groups/InputTabs.mdx';

# Input

You must provide an input so we can load your OpenAPI specification.

## Input

The input can be a string path, URL, [API registry](#api-registry), an object containing any of these, or an object representing an OpenAPI specification. Hey API supports all valid OpenAPI versions and file formats.

<InputTabs />

You can learn more about complex use cases in the [Advanced](/docs/openapi/typescript/configuration#advanced) section.

:::tip
If you use an HTTPS URL with a self-signed certificate in development, you will need to set [`NODE_TLS_REJECT_UNAUTHORIZED=0`](https://github.com/hey-api/hey-api/issues/276#issuecomment-2043143501) in your environment.
:::

### Request options

You can pass any valid Fetch API [options](https://developer.mozilla.org/docs/Web/API/RequestInit) to the request for fetching your specification. This is useful if your file is behind auth for example.

```js {4-8} title="openapi-ts.config.ts"
export default {
  input: {
    path: 'https://secret.com/protected-spec',
    fetch: {
      headers: {
        Authorization: 'Bearer xxx',
      },
    },
  },
};
```

## API Registry

You can store your specifications in an API registry to serve as a single source of truth. This helps prevent drift, improves discoverability, enables version tracking, and more.

### Hey API

You can learn more about [Hey API Platform](https://app.heyapi.dev) on the [Integrations](/docs/openapi/typescript/integrations) page.

```js {2} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
};
```

The `input` object lets you provide additional options to construct the correct URL.

```js {4} title="openapi-ts.config.ts"
export default {
  input: {
    path: 'hey-api/backend', // sign up at app.heyapi.dev
    branch: 'main',
  },
};
```

We also provide shorthands for other registries:

<details>
<summary>ReadMe</summary>
Prefix your input with `readme:` to use the ReadMe API Registry.

<Tabs>
  <TabItem label="uuid">
```js {2} title="openapi-ts.config.ts"
export default {
  input: 'readme:nysezql0wwo236',
};
```
  </TabItem>
  <TabItem label="long">
```js {2} title="openapi-ts.config.ts"
export default {
  input: 'readme:@developers/v2.0#nysezql0wwo236',
};
```
  </TabItem>
</Tabs>
</details>

<details>
<summary>Scalar</summary>
Prefix your input with `scalar:` to use the Scalar API Registry.

```js {2} title="openapi-ts.config.ts"
export default {
  input: 'scalar:@scalar/access-service',
};
```

</details>

## Watch Mode

:::caution
Watch mode currently supports only remote files via URL.
:::

If your schema changes frequently, you may want to automatically regenerate the output during development. To watch your input file for changes, enable `input.watch` mode in your configuration or pass the `--watch` flag to the CLI.

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: {
    path: 'hey-api/backend', // sign up at app.heyapi.dev
    watch: true,
  },
};
```
  </TabItem>
  <TabItem label="cli">
```sh "-w"
npx @hey-api/openapi-ts -i hey-api/backend -o src/client -w
```
  </TabItem>
</Tabs>

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Configuration Output (`web/src/content/docs/docs/openapi/typescript/configuration/output.mdx`)

---
title: Output
description: Configure @hey-api/openapi-ts.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import OutputTabs from '@/components/code-groups/OutputTabs.mdx';

# Output

You must set the output so we know where to generate your files.

## Output

Output can be a path to the destination folder or an object containing the destination folder path and optional settings.

<OutputTabs />

You can learn more about complex use cases in the [Advanced](/docs/openapi/typescript/configuration#advanced) section.

## File

Control how files are named and annotated in the generated output.

### File Name

You can customize the naming and casing pattern for files using the `fileName` option.

<Tabs>
  <TabItem label="default">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    fileName: '{{name}}',
    path: 'src/client',
  },
};
```
  </TabItem>
  <TabItem label="snake_case">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    fileName: {
      case: 'snake_case',
    },
    path: 'src/client',
  },
};
```
  </TabItem>
</Tabs>

By default, we append every file name with a `.gen` suffix to highlight it's automatically generated. You can customize or disable this suffix using the `fileName.suffix` option.

<Tabs>
  <TabItem label="default">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    fileName: {
      suffix: '.gen',
    },
    path: 'src/client',
  },
};
```
  </TabItem>
  <TabItem label="disabled">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    fileName: {
      suffix: null,
    },
    path: 'src/client',
  },
};
```
  </TabItem>
  <TabItem label="custom">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    fileName: {
      suffix: '.generated',
    },
    path: 'src/client',
  },
};
```
  </TabItem>
</Tabs>

### File Header

The generated output includes a notice in every file warning that any modifications will be lost when the files are regenerated. You can customize or disable this notice using the `header` option.

<Tabs>
  <TabItem label="example">
```js title="index.gen.ts"
/* eslint-disable */
// This file is auto-generated by @hey-api/openapi-ts

/** ... */
```
  </TabItem>
  <TabItem label="config">
```js {4-7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    header: (ctx) => [
      '/* eslint-disable */',
      ...ctx.defaultValue,
    ],
    path: 'src/client',
  },
};
```
  </TabItem>
</Tabs>

## Module

Control how module specifiers are generated in the output.

### Module Extension

Set `module.extension` to define the file extension used in import specifiers. This is useful when targeting environments that require fully specified imports (e.g., Node ESM or certain bundlers).

<Tabs>
  <TabItem label="example">
```js title="index.gen.ts"
import foo from './foo.js';
import bar from './bar.js';
```
  </TabItem>
  <TabItem label="config">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    module: {
      extension: '.js',
    },
    path: 'src/client',
  },
};
```
  </TabItem>
</Tabs>

### Module Path

Use `module.resolve` for full control over how module specifiers are generated. This lets you override specific modules or redirect them to custom locations (e.g., CDNs or internal aliases).

<Tabs>
  <TabItem label="example">
```js title="index.gen.ts"
import * as z from 'https://esm.sh/zod';
```
  </TabItem>
  <TabItem label="config">
```js {5-9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    module: {
      resolve(path) {
        if (path === 'zod') {
          return 'https://esm.sh/zod';
        }
      },
    },
    path: 'src/client',
  },
};
```
  </TabItem>
</Tabs>

## Source

Source is a copy of the input specification used to generate your output. It can be used to power documentation tools or to persist a stable snapshot alongside your generated files.

Enabling the `source` option with `true` creates a `source.json` file in your output folder.

```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    source: true,
  },
};
```

You can customize the file name and location using `fileName` and `path`. For example, this configuration will create an `openapi.json` file inside `src/client/source` directory.

```js {6-7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    source: {
      fileName: 'openapi',
      path: './source',
    },
  },
};
```

To use the source without writing it to disk, you can provide a `callback` function. This is useful for logging or integrating with external systems.

```js {6-7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    source: {
      callback: (source) => console.log(source),
      path: null,
    },
  },
};
```

## Post Process

Post-processing allows you to run commands on the generated output folder after files are written. This is typically used to run formatters, linters, or other cleanup tools.

Commands are executed in order, and each command receives the output path via the `path` placeholder.

### Presets

You can use built-in presets for common tools:

<Tabs>
  <TabItem label="biome:check">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    postProcess: ['biome:check'],
  },
};
```
  </TabItem>
  <TabItem label="biome:format">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    postProcess: ['biome:format'],
  },
};
```
  </TabItem>
  <TabItem label="biome:lint">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    postProcess: ['biome:lint'],
  },
};
```
  </TabItem>
  <TabItem label="eslint">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    postProcess: ['eslint'],
  },
};
```
  </TabItem>
  <TabItem label="oxfmt">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    postProcess: ['oxfmt'],
  },
};
```
  </TabItem>
  <TabItem label="oxlint">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    postProcess: ['oxlint'],
  },
};
```
  </TabItem>
  <TabItem label="prettier">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    postProcess: ['prettier'],
  },
};
```
  </TabItem>
</Tabs>

### Custom

You can also provide custom post processors:

```js {5-10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    postProcess: [
      {
        command: 'dprint',
        args: ['fmt', '{{path}}'],
      },
    ],
  },
};
```

You can skip processing by adding the output path to the tool's ignore file (for example `.eslintignore` or `.prettierignore`).

## Name Conflicts

As your project grows, the chances of name conflicts increase. We use a simple conflict resolver that appends numeric suffixes to duplicate identifiers. If you prefer a different strategy, you can provide your own `nameConflictResolver` function.

<Tabs>
  <TabItem label="config">
```js {4-6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    nameConflictResolver({ attempt, baseName }) {
      return attempt === 0 ? baseName : `${baseName}_N${attempt + 1}`;
    },
    path: 'src/client',
  },
};
```
  </TabItem>
  <TabItem label="example">
```ts title="index.gen.ts"
export type ChatCompletion = string;

export type ChatCompletion_N2 = number;
```
  </TabItem>
</Tabs>

## TSConfig Path

We use the [TSConfig file](https://www.typescriptlang.org/tsconfig/) to generate output matching your project's settings. By default, we attempt to find a TSConfig file starting from the location of the `@hey-api/openapi-ts` configuration file and traversing up.

<Tabs>
  <TabItem label="default">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    tsConfigPath: undefined,
  },
};
```
  </TabItem>
  <TabItem label="custom">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    tsConfigPath: './config/tsconfig.custom.json',
  },
};
```
  </TabItem>
  <TabItem label="disabled">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    path: 'src/client',
    tsConfigPath: null,
  },
};
```
  </TabItem>
</Tabs>

## Custom Files

By default, you can't keep custom files in the `path` folder because it's emptied on every run. If you're sure you need to disable this behavior, set `clean` to `false`.

```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: {
    clean: false,
    path: 'src/client',
  },
};
```

:::caution
Setting `clean` to `false` may result in broken output. Ensure you typecheck your code.
:::

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Configuration Parser (`web/src/content/docs/docs/openapi/typescript/configuration/parser.mdx`)

---
title: Parser
description: Configure @hey-api/openapi-ts.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

# Parser

We parse your input before making it available to plugins. Configuring the parser is optional, but it provides an ideal opportunity to modify or validate your input as needed.

## Patch

Sometimes you need to modify raw input before it's processed further. A common use case is fixing an invalid specification or adding a missing field. For this reason, custom patches are applied before any parsing takes place.

You can add custom patches with `patch`.

```js {7-23} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    patch: {
      schemas: {
        Foo: (schema) => {
          // convert date-time format to timestamp
          delete schema.properties.updatedAt.format;
          schema.properties.updatedAt.type = 'number';
        },
        Bar: (schema) => {
          // add missing property
          schema.properties.meta = {
            additionalProperties: true,
            type: 'object',
          };
          schema.required = ['meta'];
        },
        Baz: (schema) => {
          // remove property
          delete schema.properties.internalField;
        },
      },
    },
  },
};
```

## Validate

:::caution
The validator feature is very limited. You can help improve it by submitting more [use cases](https://github.com/hey-api/hey-api/issues/1970#issuecomment-2933189789).
:::

If you don't control or trust your input, you might want to validate it. Any detected errors in your input will exit `@hey-api/openapi-ts` and no plugins will be executed.

To validate your input, set `validate_EXPERIMENTAL` to `true`.

```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    validate_EXPERIMENTAL: true,
  },
};
```

## Filters

Filters allow you to trim your input before it's processed further, so your output contains only relevant resources.

### Operations

Set `include` to match operations to be included or `exclude` to match operations to be excluded. Both exact keys and regular expressions are supported. When both rules match the same operation, `exclude` takes precedence over `include`.

<Tabs>
  <TabItem label="include">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      operations: {
        include: ['GET /api/v1/foo', '/^[A-Z]+ /api/v1//'],
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="exclude">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      operations: {
        exclude: ['GET /api/v1/foo', '/^[A-Z]+ /api/v1//'],
      },
    },
  },
};
```
  </TabItem>
</Tabs>

### Tags

Set `include` to match tags to be included or `exclude` to match tags to be excluded. When both rules match the same tag, `exclude` takes precedence over `include`.

<Tabs>
  <TabItem label="include">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      tags: {
        include: ['v2'],
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="exclude">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      tags: {
        exclude: ['v1'],
      },
    },
  },
};
```
  </TabItem>
</Tabs>

### Deprecated

You can filter out deprecated resources by setting `deprecated` to `false`.

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      deprecated: false,
    },
  },
};
```

### Schemas

Set `include` to match schemas to be included or `exclude` to match schemas to be excluded. Both exact keys and regular expressions are supported. When both rules match the same schema, `exclude` takes precedence over `include`.

<Tabs>
  <TabItem label="include">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      schemas: {
        include: ['Foo', '/^Bar/'],
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="exclude">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      schemas: {
        exclude: ['Foo', '/^Bar/'],
      },
    },
  },
};
```
  </TabItem>
</Tabs>

### Parameters

Set `include` to match parameters to be included or `exclude` to match parameters to be excluded. Both exact keys and regular expressions are supported. When both rules match the same parameter, `exclude` takes precedence over `include`.

<Tabs>
  <TabItem label="include">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      parameters: {
        include: ['QueryParameter', '/^MyQueryParameter/'],
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="exclude">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      parameters: {
        exclude: ['QueryParameter', '/^MyQueryParameter/'],
      },
    },
  },
};
```
  </TabItem>
</Tabs>

### Request Bodies

Set `include` to match request bodies to be included or `exclude` to match request bodies to be excluded. Both exact keys and regular expressions are supported. When both rules match the same request body, `exclude` takes precedence over `include`.

<Tabs>
  <TabItem label="include">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      requestBodies: {
        include: ['Payload', '/^SpecialPayload/'],
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="exclude">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      requestBodies: {
        exclude: ['Payload', '/^SpecialPayload/'],
      },
    },
  },
};
```
  </TabItem>
</Tabs>

### Responses

Set `include` to match responses to be included or `exclude` to match responses to be excluded. Both exact keys and regular expressions are supported. When both rules match the same response, `exclude` takes precedence over `include`.

<Tabs>
  <TabItem label="include">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      responses: {
        include: ['Foo', '/^Bar/'],
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="exclude">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      responses: {
        exclude: ['Foo', '/^Bar/'],
      },
    },
  },
};
```
  </TabItem>
</Tabs>

### Orphaned resources

If you only want to exclude orphaned resources, set `orphans` to `false`. This is the default value when combined with any other filters. If this isn't the desired behavior, you may want to set `orphans` to `true` to always preserve unused resources.

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      orphans: false,
    },
  },
};
```

### Order

For performance reasons, we don't preserve the original order when filtering out resources. If maintaining the original order is important to you, set `preserveOrder` to `true`.

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    filters: {
      preserveOrder: true,
    },
  },
};
```

## Transforms

You can think of transforms as deterministic [patches](#patch). They provide an easy way to apply the most commonly used input transformations.

### Enums

Your input might contain two types of enums:

- enums defined as reusable components (root enums)
- non-reusable enums nested within other schemas (inline enums)

You may want all enums to be reusable. This is because only root enums are typically exported by plugins. Inline enums will never be directly importable since they're nested inside other schemas.

<Tabs>
  <TabItem label="root">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    transforms: {
      enums: 'root',
    },
  },
};
```
  </TabItem>
  <TabItem label="inline">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    transforms: {
      enums: 'inline',
    },
  },
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `enums` schemas using the `.name` and `.case` options.

### Properties required by default

By default, any object schema with a missing `required` keyword is interpreted as "no properties are required." This is the correct behavior according to the OpenAPI standard. However, some specifications interpret a missing `required` keyword as "all properties should be required."

This option allows you to change the default behavior so that properties are required by default unless explicitly marked as optional.

<Tabs>
  <TabItem label="default">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    transforms: {
      propertiesRequiredByDefault: false,
    },
  },
};
```
  </TabItem>
  <TabItem label="required">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    transforms: {
      propertiesRequiredByDefault: true,
    },
  },
};
```
  </TabItem>
</Tabs>

### Read-write

Your schemas might contain read-only or write-only fields. Using such schemas directly could mean asking the user to provide a read-only field in requests, or expecting a write-only field in responses. We separate schemas for requests and responses if direct usage would result in such scenarios.

<Tabs>
  <TabItem label="default">
```js {7-8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    transforms: {
      readWrite: {
        requests: '{{name}}Writable',
        responses: '{{name}}',
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="disabled">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    transforms: {
      readWrite: false,
    },
  },
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `requests` and `responses` schemas using the `.name` and `.case` options.

### Schema Name

Sometimes your schema names are auto-generated or follow a naming convention that produces verbose or awkward type names. You can rename schema component keys throughout the specification, automatically updating all `$ref` pointers. For example, stripping version markers from schema names, removing vendor prefixes, converting naming conventions, or shortening deeply qualified names.

<Tabs>
  <TabItem label="function">
```js {6-16} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    transforms: {
      schemaName: (name) => {
        // Strip version markers: ServiceRoot_v1_20_0_ServiceRoot → ServiceRoot
        let clean = name.replace(
          /([A-Za-z\d]+)_v\d+_\d+_\d+_([A-Za-z\d]*)/g,
          (_, p1, p2) => (p2.startsWith(p1) ? p2 : p1 + p2),
        );
        // Deduplicate prefixes: Foo_Foo → Foo
        const m = clean.match(/^([A-Za-z\d]+)_\1([A-Za-z\d]*)$/);
        if (m) clean = m[1] + m[2];
        return clean;
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="template">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    transforms: {
      schemaName: 'Api{{name}}',
    },
  },
};
```
  </TabItem>
</Tabs>

:::note[Name Collisions]
If a transformed schema name conflicts with an existing schema, the rename is skipped for that schema to prevent overwrites. The original name is preserved.
:::

## Pagination

Paginated operations are detected by having a pagination keyword in its parameters or request body. By default, we consider the following to be pagination keywords: `after`, `before`, `cursor`, `offset`, `page`, and `start`.

You can provide custom pagination keywords using `pagination.keywords`.

<Tabs>
  <TabItem label="extend">
```js {9-12} title="openapi-ts.config.ts"
import { defaultPaginationKeywords } from '@hey-api/openapi-ts';

export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    pagination: {
      keywords: [
        ...defaultPaginationKeywords,
        'extra',
        'pagination',
        'keywords',
      ],
    },
  },
};
```
  </TabItem>
  <TabItem label="override">
```js {7-9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    pagination: {
      keywords: [
        'custom',
        'pagination',
        'keywords',
      ],
    },
  },
};
```
  </TabItem>
</Tabs>

## Hooks

Hooks affect runtime behavior but aren't tied to any single plugin. They can be configured globally via `hooks` or per plugin through the `$hooks` property.

<Tabs>
  <TabItem label="parser">
```js {5} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    hooks: {}, // configure global hooks
  },
};
```
  </TabItem>
  <TabItem label="plugin">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@tanstack/react-query',
      $hooks: {}, // configure plugin hooks
    },
  ],
};
```
  </TabItem>
</Tabs>

We always use the first hook that returns a value. If a hook returns no value, we fall back to less specific hooks until one does.

<h3 id="hooks-operations">Operations</h3>

Each operation has a list of classifiers that can include `query`, `mutation`, both, or none. Plugins may use these values to decide whether to generate specific output. For example, you usually don't want to generate [TanStack Query options](/docs/openapi/typescript/plugins/tanstack-query#queries) for PATCH operations.

<h4 id="hooks-query-operations">Query operations</h4>

By default, GET operations are classified as `query` operations.

<h4 id="hooks-mutation-operations">Mutation operations</h4>

By default, DELETE, PATCH, POST, and PUT operations are classified as `mutation` operations.

#### Example: POST search query

Imagine your API has a POST `/search` endpoint that accepts a large payload. By default, it's classified as a `mutation`, but in practice it behaves like a `query`, and your [state management](/docs/openapi/typescript/state-management) plugin should generate query hooks.

You can achieve this by classifying the operation as `query` in a matcher.

<Tabs>
  <TabItem label="isQuery">
```js {8-10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    hooks: {
      operations: {
        isQuery: (op) => {
          if (op.method === 'post' && op.path === '/search') {
            return true;
          }
        },
      },
    },
  },
};
```
  </TabItem>
  <TabItem label="getKind">
```js {8-10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    hooks: {
      operations: {
        getKind: (op) => {
          if (op.method === 'post' && op.path === '/search') {
            return ['query'];
          }
        },
      },
    },
  },
};
```
  </TabItem>
</Tabs>

<h3 id="hooks-symbols">Symbols</h3>

Each symbol can have a placement function deciding its output location.

#### Example: Alphabetic sort

While we work on a better example, let's imagine a world where it's desirable to place every symbol in a file named after its initial letter. For example, a function named `Foo` should end up in the file `f.ts`.

You can achieve this by using the symbol's name.

```js {7-11} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  parser: {
    hooks: {
      symbols: {
        getFilePath: (symbol) => {
          if (symbol.name) {
            return symbol.name[0]?.toLowerCase();
          }
        },
      },
    },
  },
};
```

Most plugins expose configuration options that allow you to rename many of the generated symbols. If you need even more control, use the `getName()` hook.

#### Example: Enum naming

By default, generated enums use the same name for both the type and the runtime value.

<Tabs>
  <TabItem label="example">
```ts title="index.gen.ts"
export const Flags = {
  ALPHA: 'alpha',
  BETA: 'beta',
} as const;

export type Flags = (typeof Flags)[keyof typeof Flags];
```
  </TabItem>
  <TabItem label="config">
```js title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      enums: 'javascript',
      name: '@hey-api/typescript',
    },
  ],
};
```
  </TabItem>
</Tabs>

While this code works perfectly fine due to TypeScript's declaration merging, let's say we want to use a different name for the type. We can accomplish this with the `getName()` hook.

<Tabs>
  <TabItem label="example">
```ts title="index.gen.ts" "FlagsType"
export const Flags = {
  ALPHA: 'alpha',
  BETA: 'beta',
} as const;

export type FlagsType = (typeof Flags)[keyof typeof Flags];
```
  </TabItem>
  <TabItem label="config">
```js {10-14} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      enums: 'javascript',
      name: '@hey-api/typescript',
      $hooks: {
        symbols: {
          getName({ meta, name, schema }) {
            if (schema?.type === 'enum' && meta.category === 'type') {
              return `${name}Type`;
            }
          },
        },
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Configuration Vite (`web/src/content/docs/docs/openapi/typescript/configuration/vite.mdx`)

---
title: Vite Plugin
description: Integrate @hey-api/openapi-ts into your Vite 5, 6, 7, or 8 build pipeline with the official Vite plugin.
sidebar:
  label: Vite
---

import Examples from '@/components/Examples.astro';
import InstallCommand from '@/components/package-managers/InstallCommand.astro';

# Vite

### About

[Vite](https://vite.dev) is a blazing fast frontend build tool powering the next generation of web applications.

The Vite plugin integrates `@hey-api/openapi-ts` into the Vite build pipeline, running automatically whenever Vite resolves its configuration – no separate script or manual step required.

## Features

- runs automatically as part of your Vite build
- reads your existing [configuration](/docs/openapi/typescript/get-started) (or accepts inline config)
- supports Vite 5, 6, 7, and 8

## Installation

You can download `@hey-api/vite-plugin` from npm using your favorite package manager.

<InstallCommand packageName="@hey-api/vite-plugin" />

## Usage

Add the plugin to your `vite.config.ts`:

```js title="vite.config.ts"
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [heyApiPlugin()],
});
```

The plugin will automatically pick up your [configuration](/docs/openapi/typescript/configuration) file. You can also pass options inline using the `config` option:

```js title="vite.config.ts"
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    heyApiPlugin({
      config: {
        input: 'hey-api/backend', // sign up at app.heyapi.dev
        output: 'src/client',
      },
    }),
  ],
});
```

## Vite Options

You can pass Vite Plugin API options using the `vite` option. For example, to run the plugin only during development:

```js title="vite.config.ts"
import { heyApiPlugin } from '@hey-api/vite-plugin';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    heyApiPlugin({
      config: {
        input: 'hey-api/backend', // sign up at app.heyapi.dev
        output: 'src/client',
      },
      vite: {
        apply: 'serve',
      },
    }),
  ],
});
```

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Adonis (`web/src/content/docs/docs/openapi/typescript/plugins/adonis.mdx`)

---
title: AdonisJS
description: AdonisJS plugin for Hey API. Compatible with all our features.
sidebar:
  label: Adonis
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# AdonisJS

<FeatureStatus issueNumber={2364} status="planned" />

### About

[AdonisJS](https://adonisjs.com) is a TypeScript-first web framework for building web apps and API servers. It comes with support for testing, modern tooling, an ecosystem of official packages, and more.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Ajv (`web/src/content/docs/docs/openapi/typescript/plugins/ajv.mdx`)

---
title: Ajv
description: Ajv plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Ajv

<FeatureStatus issueNumber={1476} status="planned" />

### About

[Ajv](https://ajv.js.org) is the fastest JSON validator for Node.js and browser.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Arktype (`web/src/content/docs/docs/openapi/typescript/plugins/arktype.mdx`)

---
title: Arktype
description: Arktype plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Arktype

<FeatureStatus issueNumber={1473} status="planned" />

### About

[Arktype](https://arktype.io) is a TypeScript's 1:1 validator, optimized from editor to runtime.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Chance (`web/src/content/docs/docs/openapi/typescript/plugins/chance.mdx`)

---
title: Chance
description: Chance plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Chance

<FeatureStatus issueNumber={2497} status="planned" />

### About

[Chance](https://chancejs.com/) is a minimalist generator of random strings, numbers, etc. to help reduce some monotony particularly while writing automated tests or anywhere else you need anything random.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Custom (`web/src/content/docs/docs/openapi/typescript/plugins/custom.mdx`)

---
title: Custom Plugin
description: Learn how to create your own Hey API plugin.
sidebar:
  label: Plugin
---

import { FileTree, Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';

:::caution
Plugin API is in development. The interface might change before it becomes stable. We encourage you to leave feedback on [GitHub](https://github.com/hey-api/hey-api/issues).
:::

You may need to write your own plugin if the available plugins do not suit your needs or you're working on a proprietary use case. This can be easily achieved using the Plugin API. But don't take our word for it – all Hey API plugins are written this way!

## File Structure

We recommend following the design pattern of the native plugins. You can browse the code on [GitHub](https://github.com/hey-api/hey-api/tree/main/packages/openapi-ts/src/plugins) as you follow this tutorial.

<FileTree>
- my-plugin/
  - config.ts
  - imports.ts
  - index.ts
  - plugin.ts
  - types.ts
</FileTree>

First, create a `my-plugin` folder for your plugin files. Inside, create a barrel file `index.ts` exporting the plugin.

```ts title="index.ts"
export { defaultConfig, defineConfig } from './config';
export type { MyPlugin } from './types';
```

## Types

`index.ts` references two files, so we need to create them. `types.ts` contains the TypeScript interface for your plugin options.

```ts title="types.ts"
import type { DefinePlugin, Plugin } from '@hey-api/openapi-ts';

export type UserConfig = Plugin.Name<'my-plugin'> &
  Plugin.Hooks &
  Plugin.UserExports & {
    /**
     * User-configurable option for your plugin.
     */
    user?: number | string | {
      age?: number;
      name?: string;
    };
  };

export type Config = Plugin.Name<'my-plugin'> &
  Plugin.Hooks &
  Plugin.Exports & {
    /** Resolved option for your plugin. */
    user: {
      age: number;
      name: string;
    };
  };

export type MyPlugin = DefinePlugin<UserConfig, Config>;
```

- `Plugin.Name` sets the plugin's unique identifier.
- `Plugin.Hooks` allows users to override plugin behavior through event hooks. For example, users can control how schemas are extracted or how symbols are routed to files.
- `Plugin.Exports` add the `includeInEntry` option, which controls whether your plugin's exports are re-exported from the output entry file.
- `UserConfig` is what users write in their config file. `Config` is the fully resolved shape your handler receives.

## Configuration

`config.ts` defines the runtime configuration for your plugin, including how user input is resolved into `Config` and the `handler` function that generates output.

```ts title="config.ts"
import { definePluginConfig } from '@hey-api/openapi-ts';

import { handler } from './plugin';
import type { MyPlugin } from './types';

export const defaultConfig: MyPlugin['Config'] = {
  config: {
    user: {
      age: 42,
      name: 'Stan Smith',
    },
  },
  handler,
  name: 'my-plugin',
};

/**
 * Type helper for `my-plugin` plugin, returns {@link Plugin.Config} object
 */
export const defineConfig = definePluginConfig(defaultConfig);
```

The `config` table is a declarative resolution spec. Each field declares its default value and optional coercion rules. To allow users to set either `age` or `name` through the `user` field, we can add coercion rules to transform primitive values into the expected shape.

<Tabs>
  <TabItem label="config">
```ts {9-12} title="config.ts"
import { definePluginConfig } from '@hey-api/openapi-ts';

import { handler } from './plugin';
import type { MyPlugin } from './types';

export const defaultConfig: MyPlugin['Config'] = {
  config: {
    user: {
      $coerce: {
        number: (v) => ({ age: v }),
        string: (v) => ({ name: v }),
      },
      age: 42,
      name: 'Stan Smith',
    },
  },
  handler,
  name: 'my-plugin',
};

/**
 * Type helper for `my-plugin` plugin, returns {@link Plugin.Config} object
 */
export const defineConfig = definePluginConfig(defaultConfig);
```
  </TabItem>
  <TabItem label="input">
```js {8} title="openapi-ts.config.ts"
import { defineConfig } from 'path/to/my-plugin';

export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    defineConfig({
      user: 'Joe Doe', // or number to set age
    }),
  ],
};
```
  </TabItem>
  <TabItem label="resolved">
```ts
{
  user: {
    age: 42,
    name: 'Joe Doe'
  }
}
```
  </TabItem>
</Tabs>

### Dependencies

Plugins can declare dependencies on other plugins. A dependency will always be included in the output, even if the user hasn't explicitly added it to their `plugins` config. This is useful when your plugin's output builds on another plugin's types or symbols.

```ts {3} title="config.ts"
export const defaultConfig: MyPlugin['Config'] = {
  config: { ... },
  dependencies: ['@hey-api/typescript'],
  handler,
  name: 'my-plugin',
};
```

#### Resolving tags

Some dependencies aren't known at authoring time, such as which validator plugin the user has installed. Use `resolveTag` inside a `coerce()` call to look up the active plugin for a given tag at resolution time. In most cases, you'll also want to declare a dependency on the field to ensure it's included in the output.

```ts {1,2,6,9} title="config.ts"
import type { PluginContext } from '@hey-api/openapi-ts';
import { coerce } from '@hey-api/openapi-ts';

export const defaultConfig: MyPlugin['Config'] = {
  config: {
    $dependencies: ['validator'],
    validator: coerce((value, context) => {
      if (value === true || value === undefined) {
        return (context as PluginContext).resolveTag('validator');
      }
      return value;
    }),
  },
  dependencies: ['@hey-api/typescript'],
  handler,
  name: 'my-plugin',
};
```

## Handler

The `handler` function generates the actual output. We recommend implementing it in `plugin.ts`.

```ts title="plugin.ts"
import { $ } from '@hey-api/openapi-ts';

import type { MyPlugin } from './types';

export const handler: MyPlugin['Handler'] = ({ plugin }) => {
  plugin.forEach('operation', 'schema', (event) => {
    if (event.type === 'operation') {
      // do something with the operation
    } else if (event.type === 'schema') {
      // do something with the schema
    }
  });

  // use the TypeScript DSL to build nodes
  const symbolName = plugin.symbol('user');
  const node = $.const(symbolName)
    .export()
    .assign($.literal(plugin.config.user.name));
  plugin.node(node);
};
```

## Imports

Imports are a type-safe way to reference external symbols your plugin works with. Rather than querying or constructing identifiers manually, you declare them once and access them through `plugin.imports` anywhere in your handler.

Imports are also visible to users customizing your plugin's behavior. When a user provides hooks like `$resolvers`, they receive the `plugin` instance and can access `plugin.imports` to reference your plugin's imports directly.

<Tabs>
  <TabItem label="imports">
```ts title="imports.ts"
import type { PluginInstance } from '@hey-api/openapi-ts';

export function myPluginImports(plugin: PluginInstance) {
  const factory = plugin.symbolFactory;
  return {
    myLib: factory.register('myLib', { external: 'my-lib' }),
  };
}

export type MyPluginImports = ReturnType<typeof myPluginImports>;
```
  </TabItem>
  <TabItem label="types">
```ts {1,5} title="types.ts"
import type { MyPluginImports } from './imports';

/** ... */

export type MyPlugin = DefinePlugin<UserConfig, Config, never, MyPluginImports>;
```
  </TabItem>
  <TabItem label="config">
```ts {1,6} title="config.ts"
import { myPluginImports } from './imports';

export const defaultConfig: MyPlugin['Config'] = {
  config: { ... },
  handler,
  imports: myPluginImports,
  name: 'my-plugin',
};
```
  </TabItem>
  <TabItem label="handler">
```ts {2} title="plugin.ts"
export const handler: MyPlugin['Handler'] = ({ plugin }) => {
  const { myLib } = plugin.imports;
  // use myLib as a typed reference when building nodes
};
```
  </TabItem>
</Tabs>

## Usage

Once you're satisfied with your plugin, register it in the [configuration](/docs/openapi/typescript/configuration) file.

```js {1,7} title="openapi-ts.config.ts"
import { defineConfig } from 'path/to/my-plugin';

export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    defineConfig(),
  ],
};
```

## Output

Putting all of this together will generate the following `my-plugin.gen.ts` file.

```ts title="my-plugin.gen.ts"
export const user = 'Stan Smith';
```

Congratulations! You've successfully created your own plugin! 🎉

<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Elysia (`web/src/content/docs/docs/openapi/typescript/plugins/elysia.mdx`)

---
title: Elysia
description: Elysia plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Elysia

<FeatureStatus issueNumber={2676} status="planned" />

### About

[Elysia](https://elysiajs.com/) is an ergonomic framework for humans. TypeScript with end-to-end type safety, type integrity, and exceptional developer experience. Supercharged by Bun.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Express (`web/src/content/docs/docs/openapi/typescript/plugins/express.mdx`)

---
title: Express
description: Express plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Express

<FeatureStatus issueNumber={1484} status="planned" />

### About

[Express](https://expressjs.com) is a minimal and flexible Node.js web application framework that provides a robust set of features for web and mobile applications.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Faker (`web/src/content/docs/docs/openapi/typescript/plugins/faker.mdx`)

---
title: Faker v10 Plugin
description: Generate Faker v10 fake data from OpenAPI with the Faker plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Faker
custom:
  version: v10
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { malcolmKee } from '@/data/people';

# Faker

<FeatureStatus issueNumber={1485} status="in-progress" />

### About

[Faker](https://fakerjs.dev) is a popular library that generates fake (but reasonable) data that can be used for things such as unit testing, performance testing, building demos, and working without a completed backend.

The Faker plugin for Hey API generates factory functions from your OpenAPI spec that return realistic mock data using `@faker-js/faker`.

### Collaborators

<AuthorsList people={[malcolmKee]} />

## Features

- Faker v9 and v10 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- factory functions for reusable schema definitions, operation requests, and operation responses
- smart property name inference for realistic data (e.g. `email` &rarr; `faker.internet.email()`)
- constraint and format awareness (min/max, string formats, array bounds)
- optional property and default value handling
- dependency injection for custom faker instances (locale, seed)
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@faker-js/faker` to your plugins and you'll be ready to generate faker factories. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@faker-js/faker',
  ],
};
```

## Output

The Faker plugin will generate the following artifacts, depending on the input specification.

## Definitions

A factory function is generated for every reusable definition from your input.

<Tabs>
  <TabItem label="example">
```ts title="faker.gen.ts"
import { faker, type Faker } from '@faker-js/faker';

import type { Bar, Foo } from '../types.gen';

export const fakeFoo = (options?: Options): Foo => ({
  name: ensureFaker(options).string.sample(),
  age: ensureFaker(options).number.int({ min: 1, max: 120 }),
});

export const fakeBar = (options?: Options): Bar =>
  ensureFaker(options).helpers.arrayElement(['baz', 'qux']);
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@faker-js/faker',
      definitions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `definitions` factories using the `.name` and `.case` options.

## Requests

A single factory function is generated per operation for request data. It combines the request body, path parameters, query parameters, and headers into one object. Only keys with actual data are included.

<Tabs>
  <TabItem label="example">
```ts title="faker.gen.ts"
// body + path + query combined into one factory
export const fakeUpdatePetRequest = (options?: Options): Omit<UpdatePetData, 'url'> => {
  const f = options?.faker ?? faker;
  return {
    body: {
      name: f.string.sample(),
      tag: fakeTag(options),
    },
    path: {
      id: f.string.uuid(),
    },
    query: {
      dryRun: f.datatype.boolean(),
    },
  };
};

// body only
export const fakeCreatePetRequest = (options?: Options): Omit<CreatePetData, 'url'> => {
  const f = options?.faker ?? faker;
  return {
    body: {
      name: f.string.sample(),
    },
  };
};
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@faker-js/faker',
      requests: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `requests` factories using the `.name` and `.case` options.

## Responses

A factory function is generated for operation responses. When an operation has a single success response, the factory is unsuffixed. When multiple responses exist, each factory is suffixed with the status code.

<Tabs>
  <TabItem label="example">
```ts title="faker.gen.ts"
// single success response — unsuffixed
export const fakeCreatePetResponse = (options?: Options): CreatePetResponse => fakePet(options);

// multiple responses — suffixed with status code
export const fakeGetPetResponse200 = (options?: Options): GetPetResponses[200] => fakePet(options);

export const fakeGetPetResponse404 = (options?: Options): GetPetErrors[404] => fakeError(options);
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@faker-js/faker',
      responses: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `responses` factories using the `.name` and `.case` options.

## Smart Inference

The plugin infers semantically appropriate faker methods from property names, producing more realistic mock data without requiring explicit schema formats or annotations.

```ts
// property name "email" → faker.internet.email()
// property name "firstName" → faker.person.firstName()
// property name "city" → faker.location.city()
// property name "id" → faker.string.uuid()
// property name "age" → faker.number.int({ min: 1, max: 120 })
```

Ancestor context is also used for disambiguation. For example, `name` under a `User` schema produces `faker.person.fullName()`, while `name` under a `Company` schema produces `faker.company.name()`.

Explicit schema annotations (format, pattern, constraints) always take priority over name-based inference.

### Name Rules

You can extend or override the built-in name inference with custom `nameRules`. Rules are defined per schema type (`string` or `number`) and map property names to specific faker methods.

<Tabs>
  <TabItem label="example">
```ts title="faker.gen.ts"
export const fakeError = (options?: Options): Error => {
  const f = options?.faker ?? faker;
  return {
    code: f.number.int(),
    message: f.word.words({ count: 4 }),
  };
};

export const fakeDocument = (options?: Options): Document => {
  const f = options?.faker ?? faker;
  return {
    id: f.database.mongodbObjectId(),
    _id: f.database.mongodbObjectId(),
  };
};
```
  </TabItem>
  <TabItem label="config">
```js {8-21} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@faker-js/faker',
      nameRules: {
        string: {
          // compound rule: "message" inside an "error" schema
          'error.message': {
            fakerPath: ['word', 'words'],
            defaultArgs: { count: 4 },
          },
          // suffix rule: any property ending with "id"
          id: {
            fakerPath: ['database', 'mongodbObjectId'],
            suffixMatch: true,
          },
        },
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

Each rule requires a `fakerPath` — a tuple of `[module, method]` corresponding to a faker method (e.g. `['database', 'mongodbObjectId']` for `faker.database.mongodbObjectId()`). You can optionally provide `defaultArgs` to pass default arguments to the faker method.

**Matching strategies:**

- **Exact match** — `'email'` matches a property named `email`
- **Compound match** — `'error.message'` matches a property named `message` inside an ancestor named `error`
- **Suffix match** — `'id'` with `suffixMatch: true` matches any property ending with `id` (e.g. `userId`, `_id`)

User-provided rules take priority over built-in rules. Property names are normalized (lowercased, separators removed) before matching.

## Formats and Constraints

The plugin respects OpenAPI schema formats and constraints to generate appropriately bounded data.

**String formats:**

- `email` &rarr; `faker.internet.email()`
- `date-time` &rarr; `faker.date.recent().toISOString()`
- `date` &rarr; `faker.date.recent().toISOString().slice(0, 10)`
- `uuid` &rarr; `faker.string.uuid()`
- `uri` / `url` &rarr; `faker.internet.url()`
- `ipv4` &rarr; `faker.internet.ipv4()`
- `ipv6` &rarr; `faker.internet.ipv6()`
- `pattern` &rarr; `faker.helpers.fromRegExp(pattern)`

**Numeric constraints:**

- `minimum` / `maximum` &rarr; `faker.number.int({ min, max })`
- `exclusiveMinimum` / `exclusiveMaximum` &rarr; adjusted bounds

**String constraints:**

- `minLength` / `maxLength` &rarr; `faker.string.alpha({ length: { min, max } })`

**Array constraints:**

- `minItems` / `maxItems` &rarr; controls count in `faker.helpers.multiple()`

## Optional Properties

Required properties are always included. Optional properties are controlled by the `includeOptional` option at runtime.

```ts
const user = fakeFoo(); // includes optional properties by default
const user = fakeFoo({ includeOptional: false }); // excludes optional properties
const user = fakeFoo({ includeOptional: 0.5 }); // 50% probability per optional property
```

## Default Values

When a schema defines default values, you can control whether to use them instead of generating fake data via the `useDefault` option.

```ts
const data = fakeFoo(); // always generates fake data
const data = fakeFoo({ useDefault: true }); // uses schema defaults when available
const data = fakeFoo({ useDefault: 0.5 }); // 50% probability of using defaults
```

## Circular References

Schemas with circular references are automatically detected, whether self-referencing (a schema that refers to itself) or mutually recursive (two or more schemas that refer to each other). The generated factories use a depth counter to prevent infinite recursion, returning empty arrays or omitting optional properties once the limit is reached.

The maximum depth defaults to `10` and can be configured via the `maxCallDepth` option.

## Locale

You can configure the locale for generated faker factories. When set, the generated code imports the faker instance from the locale-specific build of `@faker-js/faker`.

<Tabs>
  <TabItem label="example">
```ts title="faker.gen.ts"
import { faker } from '@faker-js/faker/locale/de';
import type { Faker } from '@faker-js/faker';
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@faker-js/faker',
      locale: 'de',
    },
  ],
};
```
  </TabItem>
</Tabs>

See the [Faker localization guide](https://fakerjs.dev/guide/localization) for available locales.

## Deterministic Results

For snapshot testing or reproducible output, you can seed the faker instance and fix the reference date to ensure deterministic results.

```ts
import { faker } from '@faker-js/faker';

faker.seed(42);
faker.setDefaultRefDate('2026-01-01T00:00:00.000Z');

const data = fakeFoo();
// always returns the same output
```

## Custom Faker Instance

You can pass your own [faker instance](https://fakerjs.dev/api/faker.html) via the `faker` option for runtime locale switching or other customizations.

```ts
import { faker } from '@faker-js/faker/locale/de';

const data = fakeFoo({ faker });
```

<UserConfig package="openapi-ts" plugin="@faker-js/faker" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Falso (`web/src/content/docs/docs/openapi/typescript/plugins/falso.mdx`)

---
title: Falso
description: Falso plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Falso

<FeatureStatus issueNumber={2496} status="planned" />

### About

[Falso](https://ngneat.github.io/falso/) creates massive amounts of fake data in the browser and NodeJS. Tree shakeable & fully typed.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Fastify (`web/src/content/docs/docs/openapi/typescript/plugins/fastify.mdx`)

---
title: Fastify v5 Plugin
description: Generate Fastify v5 route handlers from OpenAPI with the Fastify plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Fastify
custom:
  version: v5
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { jacobCohen } from '@/data/people';

# Fastify

<FeatureStatus status="beta" />

### About

[Fastify](https://fastify.dev) is a fast and low overhead web framework for Node.js.

The Fastify plugin for Hey API generates route handlers from your OpenAPI spec, fully compatible with all core features.

### Collaborators

<AuthorsList people={[jacobCohen]} />

## Features

- Fastify v5 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe route handlers
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `fastify` to your plugins and you'll be ready to generate Fastify artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'fastify',
  ],
};
```

## Output

The Fastify plugin will generate the following artifacts, depending on the input specification.

## Route Handlers

Route handlers are generated from all endpoints. The generated interface follows the naming convention of SDK functions.

<Tabs>
  <TabItem label="example">
```ts title="fastify.gen.ts"
const fastify = Fastify();
const serviceHandlers: RouteHandlers = {
  createPets(request, reply) {
    reply.code(201).send();
  },
  listPets(request, reply) {
    reply.code(200).send([]);
  },
  showPetById(request, reply) {
    reply.code(200).send({
      id: Number(request.params.petId),
      name: 'Kitty',
    });
  },
};
fastify.register(glue, { serviceHandlers });
```
  </TabItem>
  <TabItem label="config">
```js title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'fastify',
  ],
};
```
  </TabItem>
</Tabs>

<UserConfig package="openapi-ts" plugin="fastify" />
<Examples githubExamplePath="/openapi-ts-fastify" />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Hono (`web/src/content/docs/docs/openapi/typescript/plugins/hono.mdx`)

---
title: Hono
description: Hono plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Hono

<FeatureStatus issueNumber={1483} status="planned" />

### About

[Hono](https://hono.dev) is a small, simple, and ultrafast web framework built on Web Standards. It works on any JavaScript runtime: Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Netlify, AWS Lambda, Lambda@Edge, and Node.js.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Joi (`web/src/content/docs/docs/openapi/typescript/plugins/joi.mdx`)

---
title: Joi
description: Joi plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Joi

<FeatureStatus issueNumber={1477} status="planned" />

### About

[Joi](https://joi.dev) is the most powerful schema description language and data validator for JavaScript.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Koa (`web/src/content/docs/docs/openapi/typescript/plugins/koa.mdx`)

---
title: Koa
description: Koa plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Koa

<FeatureStatus issueNumber={1482} status="planned" />

### About

[Koa](https://koajs.com) is a new web framework designed by the team behind Express, which aims to be a smaller, more expressive, and more robust foundation for web applications and APIs.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Msw (`web/src/content/docs/docs/openapi/typescript/plugins/msw.mdx`)

---
title: MSW v2 Plugin
description: Generate MSW v2 handlers from OpenAPI with the MSW plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: MSW
custom:
  version: v2
---

import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { malcolmKee } from '@/data/people';

# MSW

<FeatureStatus issueNumber={1486} status="in-progress" />

### About

[MSW](https://mswjs.io) is an API mocking library that allows you to write client-agnostic mocks and reuse them across any frameworks, tools, and environments.

The MSW plugin for Hey API generates type-safe mock handler factories from your OpenAPI spec, fully compatible with SDKs, transformers, and all core features.

### Collaborators

<AuthorsList people={[malcolmKee]} />

## Features

- MSW v2 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe mock handlers
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `msw` to your plugins and you'll be ready to generate MSW artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'msw',
  ],
};
```

## Output

The MSW plugin will generate the following artifacts, depending on the input specification.

### Handler Exports

Each operation is exported as a handler creator named `<operationId>Mock`. These use a wildcard (`*`) base URL so they match requests regardless of origin. A `getAllMocks` function is also exported.

```ts
import { getPetByIdMock, getAllMocks } from './client/msw.gen';
```

## Usage

### Static Response

The simplest way to mock an endpoint is to provide a static response object with a `result` property. The `status` property is optional — when omitted, it defaults to the operation's dominant success status code (e.g. `200`).

```ts
import { setupServer } from 'msw/node';
import { getPetByIdMock } from './client/msw.gen';

const mockServer = setupServer(
  // result only — status defaults to the dominant success code (200)
  getPetByIdMock({ result: { id: 1, name: 'Fido' } }),

  // explicit status code
  getPetByIdMock({ status: 200, result: { id: 1, name: 'Fido' } }),

  // type error if result type is incorrect
  // @ts-expect-error
  getPetByIdMock({ result: 'wrong type' }),
);
```

### Custom Resolver

For more control, pass an MSW `HttpResponseResolver` function. The resolver receives typed path parameters and request body when available.

```ts
import { delay, HttpResponse } from 'msw';
import { setupServer } from 'msw/node';
import { getPetByIdMock, updatePetMock } from './client/msw.gen';

const mockServer = setupServer(
  // custom resolver with typed params and body
  updatePetMock(async ({ request, params }) => {
    const body = await request.json();
    return HttpResponse.json({ id: Number(params.petId), ...body }, { status: 200 });
  }),

  // async resolver with delay
  getPetByIdMock(async () => {
    await delay(100);
    return HttpResponse.json({ id: 1, name: 'Fido' });
  }),
);
```

:::note
Path parameters are typed as `string` because MSW normalizes all path parameters to strings. Use `Number()` or similar conversions if you need numeric values.
:::

### Operations Without Responses

For operations that don't define a response type, the handler creator can be invoked without arguments or with a custom resolver function.

```ts
import { deletePetMock } from './client/msw.gen';

const mockServer = setupServer(
  deletePetMock(),

  deletePetMock(() => new HttpResponse(null, { status: 204 })),
);
```

### Response Examples

When your OpenAPI spec includes response examples, the generated handlers will use them as default values. This means you can call the handler without arguments and it will return the example response automatically.

```ts
import { getFooMock } from './client/msw.gen';

const mockServer = setupServer(
  // uses the example response from the OpenAPI spec as default
  getFooMock(),

  // you can still override with a custom response
  getFooMock({ result: { name: 'Custom' } }),
);
```

By default, `source` is set to `['@hey-api/examples']`, which embeds OpenAPI examples in the generated output. To disable this, set `source` to an empty array.

```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'msw',
      source: [],
    },
  ],
};
```

### All Handlers (`getAllMocks`)

The `getAllMocks` function generates handlers for all operations at once. This is useful for quickly setting up a mock server without manually listing each operation.

```ts
import { setupServer } from 'msw/node';
import { getAllMocks } from './client/msw.gen';

const server = setupServer(...getAllMocks());
```

#### `onMissingMock`

Some operations require a response argument (because they have no default example value). The `onMissingMock` option controls what happens for these operations:

- `'skip'` (default) — skips handlers that require an argument, only including operations that have default values or no response type
- `'error'` — includes all handlers, but operations without a provided response return a `501` error with the message `'[heyapi-msw] The mock of this request is not implemented.'`

```ts
// strict mode: all endpoints are mocked, missing ones return 501
const server = setupServer(...getAllMocks({ onMissingMock: 'error' }));
```

#### `overrides`

Use `overrides` to provide static responses for specific operations. The keys are handler names (operation ID suffixed with `Mock`) and the values are the same as what you'd pass to the individual handler creator.

```ts
import { setupServer } from 'msw/node';
import { getAllMocks } from './client/msw.gen';

const server = setupServer(
  ...getAllMocks({
    onMissingMock: 'skip',
    overrides: {
      getPetByIdMock: {
        result: { id: 1, name: 'Fido', photoUrls: [] },
      },
    },
  }),
);
```

When an override is provided for a required handler, it will always be included regardless of the `onMissingMock` setting.

### Custom Base URL

The individually exported handlers use a wildcard (`*`) base URL that matches requests regardless of origin. If you need handlers bound to a specific base URL, use the `createMswHandlerFactory` function:

```ts
import { setupServer } from 'msw/node';
import { createMswHandlerFactory } from './client/msw.gen';

const createMock = createMswHandlerFactory({
  baseUrl: 'http://localhost:8000',
});

const server = setupServer(createMock.getPetByIdMock({ result: { id: 1, name: 'Fido' } }));
```

When called without arguments, the factory infers the base URL from the OpenAPI spec's `servers` field.

### Handler Options

[Handler options](https://mswjs.io/docs/api/http#handler-options) can be provided. The object will be passed on to MSW helpers.

```ts
const mockServer = setupServer(getPetByIdMock({ result: { id: 1, name: 'Fido' } }, { once: true }));
```

## Known Limitations

- Query parameters are not typed in the resolver. MSW doesn't provide typed query params natively — use `new URL(request.url).searchParams` instead.
- The response type generic is omitted from `HttpResponseResolver` to avoid MSW's `DefaultBodyType` constraint issues with union and void response types.

<UserConfig package="openapi-ts" plugin="msw" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Nest (`web/src/content/docs/docs/openapi/typescript/plugins/nest.mdx`)

---
title: NestJS v11 Plugin
description: Generate NestJS v11 controller methods from OpenAPI with the NestJS plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Nest
custom:
  version: v11
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { yuriMikhin } from '@/data/people';

# NestJS

<FeatureStatus status="beta" />

### About

[Nest](https://nestjs.com) is a progressive Node.js framework for building efficient, reliable and scalable server-side applications.

The NestJS plugin for Hey API generates type-safe controller method signatures from your OpenAPI spec, fully compatible with all core features.

### Collaborators

<AuthorsList people={[yuriMikhin]} />

## Features

- NestJS v11 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe controller methods
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `nestjs` to your plugins and you'll be ready to generate NestJS artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'nestjs',
  ],
};
```

## Output

The NestJS plugin will generate the following artifacts, depending on the input specification.

## Controller Methods

Operations are grouped by their first tag into separate types.

<Tabs>
  <TabItem label="example">
```ts title="nestjs.gen.ts"
export type PetsControllerMethods = {
  createPet: (body: CreatePetData['body']) => Promise<CreatePetResponse>;
  listPets: (query?: ListPetsData['query']) => Promise<ListPetsResponse>;
  showPetById: (path: ShowPetByIdData['path']) => Promise<ShowPetByIdResponse>;
};

export type StoreControllerMethods = {
  getInventory: () => Promise<GetInventoryResponse>;
};
```
  </TabItem>
  <TabItem label="usage">
```ts title="pets.controller.ts"
import { Body, Controller, Get, Param, Post, Query } from '@nestjs/common';

import type { PetsControllerMethods } from '../client/nestjs.gen';
import type { CreatePetData, ListPetsData, ShowPetByIdData } from '../client/types.gen';

@Controller('pets')
export class PetsController implements Pick<
  PetsControllerMethods,
  'createPet' | 'listPets' | 'showPetById'
> {
  @Post()
  async createPet(@Body() body: CreatePetData['body']) {}

  @Get()
  async listPets(@Query() query?: ListPetsData['query']) {}

  @Get(':petId')
  async showPetById(@Param() path: ShowPetByIdData['path']) {}
}
```
  </TabItem>
</Tabs>

<UserConfig package="openapi-ts" plugin="nestjs" />
<Examples githubExamplePath="/openapi-ts-nestjs" />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Nock (`web/src/content/docs/docs/openapi/typescript/plugins/nock.mdx`)

---
title: Nock
description: Nock plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Nock

<FeatureStatus issueNumber={1487} status="planned" />

### About

[Nock](https://github.com/nock/nock) is an HTTP server mocking and expectations library for Node.js.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Pinia Colada (`web/src/content/docs/docs/openapi/typescript/plugins/pinia-colada.mdx`)

---
title: Pinia Colada v0 Plugin
description: Generate Pinia Colada v0 functions and query keys from OpenAPI with the Pinia Colada plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Pinia Colada
custom:
  version: v0
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';
import { joshHemphill, sebastiaanWouters, dmitriyBrolnickij } from '@/data/people';

# Pinia Colada

### About

[Pinia Colada](https://pinia-colada.esm.dev) is the perfect companion to Pinia to handle async state management in your Vue applications.

The Pinia Colada plugin for Hey API generates functions and query keys from your OpenAPI spec, fully compatible with SDKs, transformers, and all core features.

### Collaborators

<AuthorsList people={[dmitriyBrolnickij, joshHemphill, sebastiaanWouters]} />

## Features

- Pinia Colada v0 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- create query keys following the best practices
- type-safe query options and mutation options
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@pinia/colada` to your plugins and you'll be ready to generate Pinia Colada artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@pinia/colada',
  ],
};
```

:::tip
When using this plugin in a Nuxt app, prefer the [ofetch client](/docs/openapi/typescript/clients/ofetch) for universal compatibility.

The [nuxt client](/docs/openapi/typescript/clients/nuxt) is tailored for working directly with Nuxt composables (`$fetch` / `useFetch` / `useAsyncData`) and is not intended as a universal HTTP client for libraries like `@pinia/colada`.
:::

## Output

The Pinia Colada plugin will generate the following artifacts, depending on the input specification.

## Queries

Queries are generated from [query operations](/docs/openapi/typescript/configuration/parser#hooks-query-operations). The generated query functions follow the naming convention of SDK functions and by default append `Query`, e.g., `getPetByIdQuery()`.

<Tabs>
  <TabItem label="example">
```ts title="colada.gen.ts"
const query = useQuery(getPetByIdQuery, () => ({
  path: {
    petId: 1,
  },
}));
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@pinia/colada',
      queryOptions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `queryOptions` functions using the `.name` and `.case` options.

## Query Keys

Query keys contain normalized SDK function parameters and additional metadata.

<Tabs>
  <TabItem label="example">
```ts title="colada.gen.ts"
const queryKey = [
  {
    _id: 'getPetById',
    baseUrl: 'https://app.heyapi.dev',
    path: {
      petId: 1,
    },
  },
];
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@pinia/colada',
      queryKeys: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

### Tags

You can include operation tags in your query keys by setting `tags` to `true`. This will make query keys larger but provides better cache invalidation capabilities.

<Tabs>
  <TabItem label="example">
```ts {8} title="colada.gen.ts"
const key = [
  {
    _id: 'getPetById',
    baseUrl: 'https://app.heyapi.dev',
    path: {
      petId: 1,
    },
    tags: ['pets', 'one', 'get'],
  },
];
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@pinia/colada',
      queryKeys: {
        tags: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Accessing Query Keys

If you have access to the result of query options function, you can get the query key from the `key` field.

<Tabs>
  <TabItem label="example">
```ts title="colada.gen.ts"
const { key } = getPetByIdQuery({
  path: {
    petId: 1,
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@pinia/colada',
      queryOptions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `QueryKey`, e.g., `getPetByIdQueryKey()`.

<Tabs>
  <TabItem label="example">
```ts title="colada.gen.ts"
const key = getPetByIdQueryKey({
  path: {
    petId: 1,
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@pinia/colada',
      queryKeys: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `queryKeys` functions using the `.name` and `.case` options.

## Mutations

Mutations are generated from [mutation operations](/docs/openapi/typescript/configuration/parser#hooks-mutation-operations). The generated mutation functions follow the naming convention of SDK functions and by default append `Mutation`, e.g., `addPetMutation()`.

<Tabs>
  <TabItem label="example">
```ts title="colada.gen.ts"
const addPet = useMutation({
  ...addPetMutation(),
  onError: (error) => {
    console.log(error);
  },
});

addPet.mutate({
  body: {
    name: 'Kitty',
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@pinia/colada',
      mutationOptions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `mutationOptions` functions using the `.name` and `.case` options.

<UserConfig package="openapi-ts" plugin="@pinia/colada" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Playwright (`web/src/content/docs/docs/openapi/typescript/plugins/playwright.mdx`)

---
title: Playwright
description: Playwright plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Playwright

<FeatureStatus issueNumber={4310} status="planned" />

### About

[Playwright](https://playwright.dev/) is an end-to-end test framework for modern web apps. It bundles test runner, assertions, isolation, parallelization and rich tooling.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Schemas (`web/src/content/docs/docs/openapi/typescript/plugins/schemas.mdx`)

---
title: JSON Schema
description: Learn about files generated with @hey-api/openapi-ts.
sidebar:
  label: Schemas
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# JSON Schemas

Schemas are located in the `schemas.gen.ts` file. This file contains runtime schemas generated from your OpenAPI specification definitions located in `#/components/schemas`. If you're using OpenAPI 3.1, your schemas are fully JSON Schema compliant and can be used with other tools supporting JSON Schema.

## Configuration

You can modify the contents of `schemas.gen.ts` by configuring the `@hey-api/schemas` plugin. Note that you must specify the default plugins to preserve the default output.

<Tabs>
  <TabItem label="json">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/schemas',
      type: 'json',
    },
  ],
};
```
  </TabItem>
  <TabItem label="form">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/schemas',
      type: 'form',
    },
  ],
};
```
  </TabItem>
  <TabItem label="disabled">
```js del={6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@hey-api/schemas',
  ],
};
```
  </TabItem>
</Tabs>

## Output

Below is an example output generated in the `type: 'form'` style. Disabling schemas will not generate the `schemas.gen.ts` file.

```ts title="schemas.gen.ts"
export const PetSchema = {
  required: ['name'],
  properties: {
    id: {
      type: 'integer',
      format: 'int64',
      example: 10,
    },
    name: {
      type: 'string',
      example: 'doggie',
    },
  },
  type: 'object',
} as const;
```

## Usage

A great use case for schemas is client-side form input validation.

```ts title="SomeComponent.ts"
import { $Schema } from './client/schemas.gen';

const maxInputLength = $Schema.properties.text.maxLength;

if (userInput.length > maxInputLength) {
  throw new Error(`Text length can't exceed ${maxInputLength} characters!`);
}
```

<UserConfig package="openapi-ts" plugin="@hey-api/schemas" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Sdk (`web/src/content/docs/docs/openapi/typescript/plugins/sdk.mdx`)

---
title: SDK Plugin
description: Generate SDKs from OpenAPI with the SDK plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: SDK
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# SDK

### About

The SDK plugin generates a high-level, ergonomic API layer on top of the low-level HTTP client.

It exposes typed functions or methods for each operation, with built-in auth handling, configurable request and response validation, and ready-to-use code examples.

## Features

- high-level SDK layer on top of the HTTP client
- typed functions or methods per operation
- built-in authentication handling
- request and response validation
- ready-to-use code examples

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/sdk` to your plugins and you'll be ready to generate SDK artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@hey-api/sdk',
  ],
};
```

## Output

The SDK plugin supports a wide range of configuration options. This guide focuses on two main SDK formats: tree-shakeable functions and instantiable classes, but you can apply the same concepts to create more advanced configurations.

## Flat

This is the default setting. Flat SDKs support tree-shaking, which can lead to a reduced bundle size. You select flat mode by setting `operations.strategy` to `flat`.

<Tabs>
  <TabItem label="example">
```ts title="sdk.gen.ts"
import type { AddPetData } from './types.gen';

export const addPet = (options: Options<AddPetData>) => {
  /** ... */
};
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      operations: {
        strategy: 'flat',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Instance

Class SDKs do not support tree-shaking, which results in a larger bundle size, but you may prefer their syntax. You select class mode by setting `operations.strategy` to `single`.

<Tabs>
  <TabItem label="example">
```ts title="sdk.gen.ts"
import type { AddPetData } from './types.gen';

export class Sdk extends HeyApiClient {
  public addPet(options: Options<AddPetData>) {
    /** ... */
  }
}
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      operations: {
        strategy: 'single',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Name

As shown above, by default our SDK class is called `Sdk`. The first thing you'll likely want to do is change this to your preferred name, which you can do using `operation.containerName`.

<Tabs>
  <TabItem label="example">
```ts title="sdk.gen.ts" "PetStore"
import { client } from './client.gen';
import type { AddPetData, AddPetErrors, AddPetResponses } from './types.gen';

export class PetStore extends HeyApiClient {
  /** ... */
}
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      operations: {
        containerName: 'PetStore',
        strategy: 'single',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Structure

While we try to infer the SDK structure from `operationId` fields, you'll likely want to customize it further. You can do this using `operations.nesting`.

Similar to the `operations.strategy` option, we provide a few presets. However, you gain the most control by providing your own function.

To demonstrate the power of this feature, let's nest a few endpoints inside a `Pet` class and rename them. Our original `addPet()` method will now become `pet.add()`. Notice that we use the built-in `OperationPath.fromOperationId()` helper to handle the remaining operations.

<Tabs>
  <TabItem label="example">
```ts {5,11} title="sdk.gen.ts"
import { client } from './client.gen';
import type { AddPetData, AddPetErrors, AddPetResponses } from './types.gen';

export class Pet extends HeyApiClient {
  public add(options: Options<PostPetData>) {
    /** ... */
  }
}

export class PetStore extends HeyApiClient {
  get pet(): Pet {
    /** ... */
  }
}
```
  </TabItem>
  <TabItem label="config">
```js {10-18} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      operations: {
        containerName: 'PetStore',
        nesting(operation) {
          if (operation.path === '/pet/{petId}' || operation.path === '/pet') {
            return [
              'pet',
              operation.operationId?.replace(/Pet/, '') || operation.method.toLocaleLowerCase(),
            ];
          }
          return OperationPath.fromOperationId()(operation);
        },
        strategy: 'single',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Parameters

By default, all SDK methods accept an object with namespaced properties for each parameter type: `query`, `path`, `header`, and `body`.

<Tabs>
  <TabItem label="example">
```ts title="app.ts"
import { addPet } from './sdk.gen.ts';

await addPet({
  body: {
    name: 'Fluffy',
    type: 'cat',
  },
  path: {
    petId: 1234,
  },
  query: {
    color: 'red',
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      paramsStructure: 'grouped',
    },
  ],
};
```
  </TabItem>
</Tabs>

If you prefer a more compact syntax, you can set `paramsStructure` to `flat`. This will merge all parameter types into a single object, which is especially useful for endpoints with only one parameter type.

<Tabs>
  <TabItem label="example">
```ts title="app.ts"
import { addPet } from './sdk.gen.ts';

await addPet({
  color: 'red',
  name: 'Fluffy',
  petId: 1234,
  type: 'cat',
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      paramsStructure: 'flat',
    },
  ],
};
```
  </TabItem>
</Tabs>

## Auth

Most APIs require some form of authentication, which is why the SDK plugin provides built-in auth mechanisms by default. All you need to do is return the data from the `auth()` function, and the SDK will handle serialization and encoding for you. There are several ways to do this, for example on the client instance.

<Tabs>
  <TabItem label="example">
```ts title="sdk.gen.ts"
import { client } from './client.gen';

client.setConfig({
  auth() {
    return '<token>';
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      auth: true,
      name: '@hey-api/sdk',
    },
  ],
};
```
  </TabItem>
</Tabs>

:::note
The SDK plugin currently supports only the `bearer` and `basic` auth schemes. [Open an issue](https://github.com/hey-api/hey-api/issues) if you'd like support for additional mechanisms.
:::

## Validators

Validating data at runtime comes with a performance cost, which is why it's not enabled by default. To enable validation, set `validator` to `zod` or one of the available [validator plugins](/docs/openapi/typescript/validators). This will automatically add the selected plugin with its default configuration.

For a more granular approach, manually add a validator plugin and set `validator` to the plugin name or `true` to automatically select a compatible plugin. Until you customize the validator plugin, both approaches will produce the same default output.

<Tabs>
  <TabItem label="example">
```ts {5-8} title="sdk.gen.ts"
import * as v from 'valibot';

export const addPet = (options: Options<AddPetData>) =>
  (options.client ?? client).post<AddPetResponses, AddPetErrors>({
    requestValidator: async (data) =>
      await v.parseAsync(vAddPetData, data),
    responseValidator: async (data) =>
      await v.parseAsync(vAddPetResponse, data),
    /** ... */
  });
```
  </TabItem>
  <TabItem label="config">
```js {8,11} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      validator: true, // or 'valibot'
    },
    {
      name: 'valibot', // customize (optional)
      // other options
    },
  ],
};
```
  </TabItem>
</Tabs>

You can choose to validate only requests or responses.

<Tabs>
  <TabItem label="requests">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      validator: {
        request: 'zod',
      },
    },
  ],
};
```
  </TabItem>
  <TabItem label="responses">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      validator: {
        response: 'zod',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

Learn more about available validators on the [Validators](/docs/openapi/typescript/validators) page.

## Transformers

Transformers work similarly to [validators](#validators), with two differences: transformation applies to responses only, and you use the `transformer` option instead of `validator`.

<Tabs>
  <TabItem label="example">
```ts {5-6} title="sdk.gen.ts"
import * as v from 'valibot';

export const addPet = (options: Options<AddPetData>) =>
  (options.client ?? client).post<AddPetResponses, AddPetErrors>({
    responseTransformer: async (data) =>
      await v.parseAsync(vAddPetResponse, data),
    /** ... */
  });
```
  </TabItem>
  <TabItem label="config">
```js {8,11} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@hey-api/sdk',
      transformer: true, // or 'valibot'
    },
    {
      name: 'valibot', // customize (optional)
      // other options
    },
  ],
};
```
  </TabItem>
</Tabs>

Learn more about available transformers on the [Validators](/docs/openapi/typescript/validators) page.

## Metadata

Every SDK method accepts an optional `meta` object. You can use it to pass arbitrary values that aren't part of the SDK function and read them back in your [client](/docs/openapi/typescript/clients) interceptors or middleware.

```ts title="app.ts"
import { addPet } from './sdk.gen.ts';

await addPet({
  meta: {
    timeout: 5000,
  },
});
```

By default `meta` is untyped, so typos and wrong-typed values compile silently. To make it type-safe, augment the `ClientMeta` interface exported by your client. After augmentation, `meta` is fully type-checked at the call site.

<Tabs>
  <TabItem label="types">
```ts title="overrides.d.ts"
declare module '@hey-api/client-fetch' {
  interface ClientMeta {
    retry?: boolean;
    timeout?: number;
  }
}
```
  </TabItem>
  <TabItem label="usage">
```ts title="app.ts"
import { addPet } from './sdk.gen.ts';

await addPet({
  meta: {
    timeout: 5000, // ✅ correctly typed
    timeoutt: 5000, // ❌ unknown key
    retry: '5s', // ❌ wrong type
  },
});
```
  </TabItem>
</Tabs>

## Code Examples

The SDK plugin can generate ready-to-use code examples for each operation, showing how to call the SDK methods with proper parameters and setup.

Examples are not generated by default, but you can enable and customize them through the `examples` option. With the default settings, an example might look like this.

<Tabs>
  <TabItem label="example">
```ts
import { PetStore } from 'your-package';

await new PetStore().addPet();

```
  </TabItem>
  <TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      examples: true,
      name: '@hey-api/sdk',
      operations: {
        containerName: 'PetStore',
        strategy: 'single',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Module and Setup

To make examples more practical, configure `moduleName` to specify the package from which users import your SDK.

Next, set `setupName` to indicate how users should instantiate the SDK, typically only once per application.

<Tabs>
  <TabItem label="example">
```ts "@petstore/client" "client"
import { PetStore } from '@petstore/client';

const client = new PetStore();

await client.addPet();

```
  </TabItem>
  <TabItem label="config">
```js {8-9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      examples: {
        moduleName: '@petstore/client',
        setupName: 'client',
      },
      name: '@hey-api/sdk',
      operations: {
        containerName: 'PetStore',
        strategy: 'single',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Initialization

Often, your SDK needs to be instantiated with an API key or other configuration. In examples, `importSetup` lets you control how the SDK is initialized.

<Tabs>
  <TabItem label="example">
```ts {3-5}
import { PetStore } from '@petstore/client';

const client = new PetStore({
  apiKey: 'YOUR_API_KEY',
});

await client.addPet();

```
  </TabItem>
  <TabItem label="config">
```js {8-14} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      examples: {
        importSetup: ({ $, node }) =>
          $.new(
            node.name,
            $.object()
              .pretty()
              .prop('apiKey', $.literal('YOUR_API_KEY')),
          ),
        moduleName: '@petstore/client',
        setupName: 'client',
      },
      name: '@hey-api/sdk',
      operations: {
        containerName: 'PetStore',
        strategy: 'single',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Import Style

If you re-export the generated SDK from your own module, you can adjust `importName` and `importKind` to match your actual import style.

<Tabs>
  <TabItem label="example">
```ts {1} "CatStore"
import CatStore from '@petstore/client';

const client = new CatStore({
  apiKey: 'YOUR_API_KEY',
});

await client.addPet();

```
  </TabItem>
  <TabItem label="config">
```js {8-9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      examples: {
        importKind: 'default',
        importName: 'CatStore',
        importSetup: ({ $, node }) =>
          $.new(
            node.name,
            $.object()
              .pretty()
              .prop('apiKey', $.literal('YOUR_API_KEY')),
          ),
        moduleName: '@petstore/client',
        setupName: 'client',
      },
      name: '@hey-api/sdk',
      operations: {
        containerName: 'PetStore',
        strategy: 'single',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Payload

You can customize the example request using the `payload` option. Requests can also be customized selectively. For example, we can provide a default payload only for the `addPet()` method.

<Tabs>
  <TabItem label="example">
```ts {7-9}
import CatStore from '@petstore/client';

const client = new CatStore({
  apiKey: 'YOUR_API_KEY',
});

await client.addPet({
  petId: 1234,
});

```
  </TabItem>
  <TabItem label="config">
```js {18-23} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      examples: {
        importKind: 'default',
        importName: 'CatStore',
        importSetup: ({ $, node }) =>
          $.new(
            node.name,
            $.object()
              .pretty()
              .prop('apiKey', $.literal('YOUR_API_KEY')),
          ),
        moduleName: '@petstore/client',
        payload(operation, ctx) {
          const { $ } = ctx;
          if (operation.path === '/pet/{petId}' || operation.path === '/pet') {
            return $.object().pretty().prop('petId', $.literal(1234));
          }
        },
        setupName: 'client',
      },
      name: '@hey-api/sdk',
      operations: {
        containerName: 'PetStore',
        strategy: 'single',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Display

Enabling examples does not produce visible output on its own. Examples are written into the source specification and can be consumed by documentation tools. To persist that specification, enable [Source](/docs/openapi/typescript/configuration/output#source) generation.

<UserConfig package="openapi-ts" plugin="@hey-api/sdk" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Superstruct (`web/src/content/docs/docs/openapi/typescript/plugins/superstruct.mdx`)

---
title: Superstruct
description: Superstruct plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Superstruct

<FeatureStatus issueNumber={1489} status="planned" />

### About

[Superstruct](https://docs.superstructjs.org) makes it easy to define interfaces and then validate JavaScript data against them.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Supertest (`web/src/content/docs/docs/openapi/typescript/plugins/supertest.mdx`)

---
title: Supertest
description: Supertest plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Supertest

<FeatureStatus issueNumber={1488} status="planned" />

### About

[Supertest](https://github.com/ladjs/supertest) is a super-agent driven library for testing node.js HTTP servers using a fluent API.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Swr (`web/src/content/docs/docs/openapi/typescript/plugins/swr.mdx`)

---
title: SWR
description: SWR plugin for Hey API. Compatible with all our features.
sidebar:
  label: SWR
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# SWR

<FeatureStatus issueNumber={1479} status="planned" />

### About

[SWR](https://swr.vercel.app) is a strategy to first return the data from cache (stale), then send the fetch request (revalidate), and finally come with the up-to-date data.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Tanstack Query (`web/src/content/docs/docs/openapi/typescript/plugins/tanstack-query.mdx`)

---
title: TanStack Query v5 Plugin
description: Generate TanStack Query v5 functions and query keys from OpenAPI with the TanStack Query plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: TanStack Query
custom:
  version: v5
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import StackBlitz from '@/components/StackBlitz.astro';
import UserConfig from '@/components/UserConfig.astro';

# TanStack Query

### About

[TanStack Query](https://tanstack.com/query) is a powerful asynchronous state management solution for TypeScript/JavaScript, React, Solid, Vue, Svelte, Angular, and Preact.

The TanStack Query plugin for Hey API generates functions and query keys from your OpenAPI spec, fully compatible with SDKs, transformers, and all core features.

### Demo

<StackBlitz
  example="hey-api-client-fetch-plugin-tanstack-react-query-example"
  openFile={[
    'openapi-ts.config.ts',
    'src/client/@tanstack/react-query.gen.ts',
    'src/client/types.gen.ts',
    'src/App.tsx',
  ]}
/>

## Features

- TanStack Query v5 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- create query keys following the best practices
- type-safe query options, infinite query options, and mutation options
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add TanStack Query to your plugins and you'll be ready to generate TanStack Query artifacts. 🎉

<Tabs>
  <TabItem label="react">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@tanstack/react-query',
  ],
};
```
  </TabItem>
  <TabItem label="vue">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@tanstack/vue-query',
  ],
};
```
  </TabItem>
  <TabItem label="angular">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@tanstack/angular-query-experimental',
  ],
};
```
  </TabItem>
  <TabItem label="svelte">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@tanstack/svelte-query',
  ],
};
```
  </TabItem>
  <TabItem label="solid">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@tanstack/solid-query',
  ],
};
```
  </TabItem>
  <TabItem label="preact">
```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@tanstack/preact-query',
  ],
};
```
  </TabItem>
</Tabs>

## Output

The TanStack Query plugin will generate the following artifacts, depending on the input specification.

## Queries

Queries are generated from [query operations](/docs/openapi/typescript/configuration/parser#hooks-query-operations). The generated query functions follow the naming convention of SDK functions and by default append `Options`, e.g., `getPetByIdOptions()`.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const query = useQuery({
  ...getPetByIdOptions({
    path: {
      petId: 1,
    },
  }),
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      queryOptions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `queryOptions` functions using the `.name` and `.case` options.

### Meta

You can use the `meta` field to attach arbitrary information to a query. To generate metadata for `queryOptions`, provide a function to the `.meta` option.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
queryOptions({
  // ...other fields
  meta: {
    id: 'getPetById',
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      queryOptions: {
        meta: (operation) => ({ id: operation.id }),
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Query Keys

Query keys contain normalized SDK function parameters and additional metadata.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const queryKey = [
  {
    _id: 'getPetById',
    baseUrl: 'https://app.heyapi.dev',
    path: {
      petId: 1,
    },
  },
];
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      queryKeys: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

### Tags

You can include operation tags in your query keys by setting `tags` to `true`. This will make query keys larger but provides better cache invalidation capabilities.

<Tabs>
  <TabItem label="example">
```ts {8} title="react-query.gen.ts"
const queryKey = [
  {
    _id: 'getPetById',
    baseUrl: 'https://app.heyapi.dev',
    path: {
      petId: 1,
    },
    tags: ['pets', 'one', 'get'],
  },
];
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      queryKeys: {
        tags: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Accessing Query Keys

If you have access to the result of query options function, you can get the query key from the `queryKey` field.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const { queryKey } = getPetByIdOptions({
  path: {
    petId: 1,
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      queryOptions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `QueryKey`, e.g., `getPetByIdQueryKey()`.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const queryKey = getPetByIdQueryKey({
  path: {
    petId: 1,
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      queryKeys: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `queryKeys` functions using the `.name` and `.case` options.

## Infinite Queries

Infinite queries are generated from [query operations](/docs/openapi/typescript/configuration/parser#hooks-query-operations) if we detect a [pagination](/docs/openapi/typescript/configuration/parser#pagination) parameter. The generated infinite query functions follow the naming convention of SDK functions and by default append `InfiniteOptions`, e.g., `getFooInfiniteOptions()`.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const query = useInfiniteQuery({
  ...getFooInfiniteOptions({
    path: {
      fooId: 1,
    },
  }),
  getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
  initialPageParam: 0,
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      infiniteQueryOptions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `infiniteQueryOptions` functions using the `.name` and `.case` options.

### Meta

You can use the `meta` field to attach arbitrary information to a query. To generate metadata for `infiniteQueryOptions`, provide a function to the `.meta` option.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
infiniteQueryOptions({
  // ...other fields
  meta: {
    id: 'getPetById',
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      infiniteQueryOptions: {
        meta: (operation) => ({ id: operation.id }),
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Infinite Query Keys

Infinite query keys contain normalized SDK function parameters and additional metadata.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const queryKey = [
  {
    _id: 'getPetById',
    _infinite: true,
    baseUrl: 'https://app.heyapi.dev',
    path: {
      petId: 1,
    },
  },
];
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      infiniteQueryKeys: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

### Tags

You can include operation tags in your infinite query keys by setting `tags` to `true`. This will make query keys larger but provides better cache invalidation capabilities.

<Tabs>
  <TabItem label="example">
```ts {9} title="react-query.gen.ts"
const queryKey = [
  {
    _id: 'getPetById',
    _infinite: true,
    baseUrl: 'https://app.heyapi.dev',
    path: {
      petId: 1,
    },
    tags: ['pets', 'one', 'get'],
  },
];
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      infiniteQueryKeys: {
        tags: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Accessing Infinite Query Keys

If you have access to the result of infinite query options function, you can get the query key from the `queryKey` field.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const { queryKey } = getPetByIdInfiniteOptions({
  path: {
    petId: 1,
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      infiniteQueryOptions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

Alternatively, you can access the same query key by calling query key functions. The generated query key functions follow the naming convention of SDK functions and by default append `InfiniteQueryKey`, e.g., `getPetByIdInfiniteQueryKey()`.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const queryKey = getPetByIdInfiniteQueryKey({
  path: {
    petId: 1,
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      infiniteQueryKeys: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `infiniteQueryKeys` functions using the `.name` and `.case` options.

## Mutations

Mutations are generated from [mutation operations](/docs/openapi/typescript/configuration/parser#hooks-mutation-operations). The generated mutation functions follow the naming convention of SDK functions and by default append `Mutation`, e.g., `addPetMutation()`.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const addPet = useMutation({
  ...addPetMutation(),
  onError: (error) => {
    console.log(error);
  },
});

addPet.mutate({
  body: {
    name: 'Kitty',
  },
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      mutationOptions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `mutationOptions` functions using the `.name` and `.case` options.

## Mutation Keys

Mutation keys contain normalized SDK function parameters and additional metadata.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const mutationKey = [
  {
    _id: 'addPet',
    baseUrl: 'https://app.heyapi.dev',
    body: {
      name: 'Kitty',
    },
  },
];
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      mutationKeys: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

### Meta

You can use the `meta` field to attach arbitrary information to a mutation. To generate metadata for `mutationOptions`, provide a function to the `.meta` option.

<Tabs>
  <TabItem label="example">
```ts title="react-query.gen.ts"
const mutationOptions = {
  // ...other fields
  meta: {
    id: 'getPetById',
  },
};
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@tanstack/react-query',
      mutationOptions: {
        meta: (operation) => ({ id: operation.id }),
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Reactivity

In Vue applications, you need to wrap the options functions in [`computed()`](https://vuejs.org/guide/essentials/computed) to make them reactive. Otherwise, TanStack Query won't know it should execute the query when its dependencies change.

<Tabs>
  <TabItem label="reactive">
```js title="react-query.gen.ts"
// ✅ Query will execute on `petId` change
const query = useQuery(
  computed(() =>
    getPetByIdOptions({
      path: {
        petId: petId.value,
      },
    }),
  ),
);
```
  </TabItem>
  <TabItem label="static">
```js title="react-query.gen.ts"
// ❌ Query will execute only once
const query = useQuery(
  getPetByIdOptions({
    path: {
      petId: petId.value,
    },
  }),
);
```
  </TabItem>
</Tabs>

<UserConfig package="openapi-ts" plugin="@tanstack/react-query" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Tanstack Start (`web/src/content/docs/docs/openapi/typescript/plugins/tanstack-start.mdx`)

---
title: TanStack Start
description: TanStack Start plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# TanStack Start

<FeatureStatus issueNumber={3909} status="planned" />

### About

[TanStack Start](https://tanstack.com/start) is a full-stack framework powered by TanStack Router for React and Solid.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Transformers (`web/src/content/docs/docs/openapi/typescript/plugins/transformers.mdx`)

---
title: Transformers
description: Learn about transforming data with @hey-api/openapi-ts.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import UserConfig from '@/components/UserConfig.astro';

# Transformers

:::tip
If you're already using a [validator](/docs/openapi/typescript/validators) plugin such as Zod or Valibot, you can use it as a transformer too. See your validator plugin's docs for details.

Otherwise, `@hey-api/transformers` is the right choice.
:::

JSON is the most commonly used data format in REST APIs. However, it does not map well to complex data types. For example, both regular strings and date strings become simple strings in JSON.

One approach to this problem is using a [JSON superset](https://github.com/blitz-js/superjson). For most people, switching formats is not feasible. That's why we provide the `@hey-api/transformers` plugin.

## Considerations

Before deciding whether transformers are right for you, let's explain how they work. Transformers generate a runtime file, therefore they impact the bundle size. We generate a single transformer per operation response for the most efficient result, just like a human engineer would.

### Limitations

Transformers handle only the most common scenarios. Some of the known limitations are:

- union types are not transformed (e.g., if you have multiple possible response shapes)
- only types defined through `$ref` are transformed
- error responses are not transformed

If your data isn't being transformed as expected, we encourage you to leave feedback on [GitHub](https://github.com/hey-api/hey-api/issues).

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/transformers` to your plugins and you'll be ready to generate transformers. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@hey-api/transformers',
  ],
};
```

## SDKs

To transform response data in your SDKs, set `transformer` to `true` on the SDK plugin.

```js {7-10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@hey-api/transformers',
    {
      name: '@hey-api/sdk',
      transformer: true,
    },
  ],
};
```

## Dates

To convert date strings into `Date` objects, use the `dates` configuration option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      dates: true,
      name: '@hey-api/transformers',
    },
  ],
};
```

This will generate types that use `Date` instead of `string` and appropriate transformers.

### Temporal

To use the [Temporal API](https://tc39.es/proposal-temporal/docs/) via [`temporal-polyfill`](https://github.com/fullcalendar/temporal-polyfill), set `dates` to `temporal`.

<Tabs>
  <TabItem label="example">
```ts title="transformers.gen.ts"
import { Temporal } from 'temporal-polyfill';

import type { GetFooResponse } from './types.gen';

const quxSchemaResponseTransformer = (data: any) => {
  if (data.baz) {
    data.baz = Temporal.Instant.from(data.baz);
  }
  return data;
};

const bazSchemaResponseTransformer = (data: any) => {
  data = quxSchemaResponseTransformer(data);
  data.bar = Temporal.Instant.from(data.bar);
  return data;
};

export const getFooResponseTransformer = async (data: any): Promise<GetFooResponse> => {
  data = bazSchemaResponseTransformer(data);
  return data;
};
```
  </TabItem>
  <TabItem label="config">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      dates: 'temporal',
      name: '@hey-api/transformers',
    },
  ],
};
```
  </TabItem>
</Tabs>

## BigInt

The `@hey-api/transformers` plugin will natively type all BigInts as `bigint` instead of `number`, which can affect arithmetic operations if your application previously used `number`. To force BigInts to be numbers, use the `bigInt` configuration option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      bigInt: true,
      name: '@hey-api/transformers',
    },
  ],
};
```

## Example

A generated response transformer might look something like this. Please note the example has been edited for brevity.

<Tabs>
  <TabItem label="transformers.gen.ts">
```ts title="transformers.gen.ts"
import type { GetFooResponse } from './types.gen';

const quxSchemaResponseTransformer = (data: any) => {
  if (data.baz) {
    data.baz = new Date(data.baz);
  }
  return data;
};

const bazSchemaResponseTransformer = (data: any) => {
  data = quxSchemaResponseTransformer(data);
  data.bar = new Date(data.bar);
  return data;
};

export const getFooResponseTransformer = async (data: any): Promise<GetFooResponse> => {
  data = bazSchemaResponseTransformer(data);
  return data;
};
```
  </TabItem>
  <TabItem label="types.gen.ts">
```ts title="types.gen.ts"
export type Baz = Qux & {
  id: 'Baz';
} & {
  foo: number;
  bar: Date;
  baz: 'foo' | 'bar' | 'baz';
  qux: number;
};

export type Qux = {
  foo: number;
  bar: number;
  baz?: Date;
  id: string;
};

export type GetFooResponse = Baz;
```
  </TabItem>
</Tabs>

<UserConfig package="openapi-ts" plugin="@hey-api/transformers" />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Typebox (`web/src/content/docs/docs/openapi/typescript/plugins/typebox.mdx`)

---
title: TypeBox
description: TypeBox plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# TypeBox

<FeatureStatus issueNumber={1475} status="planned" />

### About

[TypeBox](https://github.com/sinclairzx81/typebox) is a JSON Schema type builder with static type resolution for TypeScript.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Typescript (`web/src/content/docs/docs/openapi/typescript/plugins/typescript.mdx`)

---
title: TypeScript
description: Learn about files generated with @hey-api/openapi-ts.
sidebar:
  label: TypeScript
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# TypeScript

TypeScript interfaces are located in the `types.gen.ts` file. This is the only file that does not impact your bundle size and runtime performance. It will get discarded during build time, unless you configured to emit runtime [enums](#enums).

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/typescript` to your plugins and you'll be ready to generate TypeScript artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@hey-api/typescript',
  ],
};
```

:::note
The `@hey-api/typescript` plugin might be automatically added to your `plugins` if another plugin depends on it.
:::

## Output

The TypeScript plugin will generate the following artifacts, depending on the input specification.

## Requests

A single request type is generated for each endpoint. It may contain a request body, parameters, and headers.

```ts title="types.gen.ts"
export type AddPetData = {
  body: {
    id?: number;
    name: string;
  };
  path?: never;
  query?: never;
  url: '/pets';
};
```

You can customize the naming and casing pattern for `requests` types using the `.name` and `.case` options.

## Responses

A single type is generated for all endpoint's responses.

```ts title="types.gen.ts"
export type AddPetResponses = {
  200: {
    id?: number;
    name: string;
  };
};

export type AddPetResponse = AddPetResponses[keyof AddPetResponses];
```

You can customize the naming and casing pattern for `responses` types using the `.name` and `.case` options.

## Definitions

A type is generated for every reusable definition from your input.

```ts title="types.gen.ts"
export type Pet = {
  id?: number;
  name: string;
};
```

You can customize the naming and casing pattern for `definitions` types using the `.name` and `.case` options.

## Enums

By default, `@hey-api/typescript` will emit enums only as types. You may want to generate runtime artifacts. A good use case is iterating through possible field values without manually typing arrays. To emit runtime enums, set `enums` to a valid option.

<Tabs>
  <TabItem label="disabled">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      enums: false, // default
      name: '@hey-api/typescript',
    },
  ],
};
```
  </TabItem>
  <TabItem label="javascript">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      enums: 'javascript',
      name: '@hey-api/typescript',
    },
  ],
};
```
  </TabItem>
  <TabItem label="typescript">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      enums: 'typescript',
      name: '@hey-api/typescript',
    },
  ],
};
```
  </TabItem>
</Tabs>

We recommend exporting enums as plain JavaScript objects. [TypeScript enums](https://www.typescriptlang.org/docs/handbook/enums.html) are not a type-level extension of JavaScript and pose [typing challenges](https://dev.to/ivanzm123/dont-use-enums-in-typescript-they-are-very-dangerous-57bh).

## Comments

By default, `@hey-api/typescript` will include comments in the generated code based on descriptions from your OpenAPI specification. If you want to reduce the size of your generated files or prefer cleaner output, you can disable comments.

<Tabs>
  <TabItem label="enabled">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      comments: true, // default
      name: '@hey-api/typescript',
    },
  ],
};
```
  </TabItem>
  <TabItem label="disabled">
```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      comments: false,
      name: '@hey-api/typescript',
    },
  ],
};
```
  </TabItem>
</Tabs>

## Resolvers

You can further customize this plugin's behavior using [resolvers](/docs/openapi/typescript/plugins/concepts/resolvers).

<UserConfig package="openapi-ts" plugin="@hey-api/typescript" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Valibot (`web/src/content/docs/docs/openapi/typescript/plugins/valibot.mdx`)

---
title: Valibot v1 Plugin
description: Generate Valibot v1 schemas from OpenAPI with the Valibot plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Valibot
custom:
  version: v1
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# Valibot

### About

[Valibot](https://valibot.dev) is the open source schema library for TypeScript with bundle size, type safety and developer experience in mind.

The Valibot plugin for Hey API generates schemas from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

## Features

- Valibot v1 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- Valibot schemas for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `valibot` to your plugins and you'll be ready to generate Valibot artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'valibot',
  ],
};
```

### SDKs

Valibot can validate or transform data directly in your SDK. Set `validator` or `transformer` to `true` on the SDK plugin to enable it.

<Tabs>
  <TabItem label="validator">
```js {7-10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'valibot',
    {
      name: '@hey-api/sdk',
      validator: true,
    },
  ],
};
```
  </TabItem>
  <TabItem label="transformer">
```js {7-10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'valibot',
    {
      name: '@hey-api/sdk',
      transformer: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

The SDK page covers [validators](/docs/openapi/typescript/plugins/sdk#validators) and [transformers](/docs/openapi/typescript/plugins/sdk#transformers) in more detail.

## Output

The Valibot plugin will generate the following artifacts, depending on the input specification.

## Requests

A Valibot schema is generated for every request layer of each endpoint.

<Tabs>
  <TabItem label="example">
```ts title="valibot.gen.ts"
const vDeletePetHeaders = v.object({
  api_key: v.optional(v.string()),
});

const vDeletePetPath = v.object({
  petId: v.number(),
});

const vDeletePetQuery = v.object({
  additionalMetadata: v.string(),
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'valibot',
      requests: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `requests` schemas using the `.name` and `.case` options.

## Responses

A single Valibot schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes.

<Tabs>
  <TabItem label="example">
```ts title="valibot.gen.ts"
const vResponse = v.union([
  v.object({
    foo: v.optional(v.string()),
  }),
  v.object({
    bar: v.optional(v.number()),
  }),
]);
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'valibot',
      responses: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `responses` schemas using the `.name` and `.case` options.

## Definitions

A Valibot schema is generated for every reusable definition from your input.

<Tabs>
  <TabItem label="example">
```ts title="valibot.gen.ts"
const vFoo = v.pipe(v.number(), v.integer());

const vBar = v.object({
  bar: v.optional(v.array(v.pipe(v.number(), v.integer()))),
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'valibot',
      definitions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `definitions` schemas using the `.name` and `.case` options.

## Metadata

It's often useful to associate a schema with some additional [metadata](https://valibot.dev/api/metadata/) for documentation, code generation, AI structured outputs, form validation, and other purposes. You can set `metadata` to `true` to attach descriptions to schemas when available.

<Tabs>
  <TabItem label="example">
```ts title="valibot.gen.ts"
export const vFoo = v.pipe(
  v.string(),
  v.metadata({
    description: 'Additional metadata',
  }),
);
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'valibot',
      metadata: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

For more control over metadata, you can provide your own function. It receives the source `schema`, the target `node` object, and the `$` builder for populating metadata.

<Tabs>
  <TabItem label="example">
```ts title="valibot.gen.ts"
export const vFoo = v.pipe(
  v.string(),
  v.metadata({
    hasTitle: false,
    createdAt: 1735732800000,
  }),
);
```
  </TabItem>
  <TabItem label="config">
```js {8-11} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'valibot',
      metadata({ $, node, schema }) {
        node.prop('hasTitle', $.literal(Boolean(schema.title)));
        node.prop('createdAt', $.literal(Date.now()));
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Resolvers

You can further customize this plugin's behavior using [resolvers](/docs/openapi/typescript/plugins/concepts/resolvers).

<UserConfig package="openapi-ts" plugin="valibot" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Yup (`web/src/content/docs/docs/openapi/typescript/plugins/yup.mdx`)

---
title: Yup
description: Yup plugin for Hey API. Compatible with all our features.
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Yup

<FeatureStatus issueNumber={1478} status="planned" />

### About

[Yup](https://github.com/jquense/yup) is a schema builder for runtime value parsing and validation.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Zustand (`web/src/content/docs/docs/openapi/typescript/plugins/zustand.mdx`)

---
title: Zustand
description: Zustand plugin for Hey API. Compatible with all our features.
sidebar:
  label: Zustand
---

import FeatureStatus from '@/components/FeatureStatus.astro';

# Zustand

<FeatureStatus issueNumber={1480} status="planned" />

### About

[Zustand](https://zustand-demo.pmnd.rs) is a small, fast, and scalable bearbones state management solution.

---

### Web Src Content Docs Docs Openapi Typescript Clients Angular V19 (`web/src/content/docs/docs/openapi/typescript/clients/angular/v19.mdx`)

---
title: Angular v19 Client
description: Generate a type-safe Angular v19 client from OpenAPI with the Angular client for openapi-ts. Fully compatible with validators, transformers, and all core features.
custom:
  version: v19
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { maxScopp } from '@/data/people';

# Angular

<FeatureStatus status="beta" />

### About

[Angular](https://angular.dev/) is a web framework that empowers developers to build fast, reliable applications.

The Angular client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

### Collaborators

<AuthorsList people={[maxScopp]} />

## Features

- Angular v19 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- support for [`@Injectable()`](https://angular.dev/api/core/Injectable) decorators
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/client-angular` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-angular'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-ts \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-angular
```
  </TabItem>
</Tabs>

### Providers

You can use the Angular client in your application by adding `provideHeyApiClient` to your providers.

```ts {6} title="src/app/app.module.ts"
import { provideHeyApiClient, client } from './client/client.gen';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withFetch()),
    provideHeyApiClient(client),
  ],
};
```

## Configuration

The Angular client is built as a thin wrapper on top of Angular, extending its functionality to work with Hey API. If you're already familiar with Angular, configuring your client will feel like working directly with Angular.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/typescript/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any `HttpRequest` configuration option to `setConfig()`, and even your own [`httpClient`](#custom-httpclient) implementation.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseUrl: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-angular',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseUrl: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. If needed, you can still use `setConfig()` to update the client configuration later.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseUrl: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseUrl: 'https://example.com', // <-- override default configuration
});
```

## `@Injectable`

If you prefer to use the [`@Injectable()`](https://angular.dev/api/core/Injectable) decorators, set the `asClass` option in your SDK plugin to `true`.

<Tabs>
  <TabItem label="example">
```ts title="src/foo.service.ts"
@Injectable({ providedIn: 'root' })
export class FooService {
  // class methods
}
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    '@hey-api/client-angular',
    {
      name: '@hey-api/sdk',
      asClass: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

## Interceptors

:::caution
This section is under construction. We appreciate your patience.
:::

## Auth

:::caution
This section is under construction. We appreciate your patience.
:::

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `httpClient` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  httpClient: inject(CustomHttpClient),
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

## Plugins

You might be also interested in the [Angular](/docs/openapi/typescript/plugins/angular/v19) plugin.

<UserConfig package="openapi-ts" plugin="@hey-api/client-angular" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Clients Angular V20 (`web/src/content/docs/docs/openapi/typescript/clients/angular/v20.mdx`)

---
title: Angular v20 Client
description: Generate a type-safe Angular v20 client from OpenAPI with the Angular client for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Angular
custom:
  version: v20
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { maxScopp } from '@/data/people';

# Angular

<FeatureStatus status="beta" />

### About

[Angular](https://angular.dev/) is a web framework that empowers developers to build fast, reliable applications.

The Angular client for Hey API generates a type-safe client from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

### Collaborators

<AuthorsList people={[maxScopp]} />

## Features

- Angular v20 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- support for [`@Injectable()`](https://angular.dev/api/core/Injectable) decorators
- response data validation and transformation
- access to the original request and response
- granular request and response customization options
- minimal learning curve thanks to extending the underlying technology
- support bundling inside the generated output

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@hey-api/client-angular` to your plugins and you'll be ready to generate client artifacts. 🎉

<Tabs>
  <TabItem label="config">
```js {4} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: ['@hey-api/client-angular'],
};
```
  </TabItem>
  <TabItem label="cli">
```sh {4}
npx @hey-api/openapi-ts \
  -i hey-api/backend \
  -o src/client \
  -c @hey-api/client-angular
```
  </TabItem>
</Tabs>

### Providers

You can use the Angular client in your application by adding `provideHeyApiClient` to your providers.

```ts {6} title="src/app/app.module.ts"
import { provideHeyApiClient, client } from './client/client.gen';

export const appConfig: ApplicationConfig = {
  providers: [
    provideHttpClient(withFetch()),
    provideHeyApiClient(client),
  ],
};
```

## Configuration

The Angular client is built as a thin wrapper on top of Angular, extending its functionality to work with Hey API. If you're already familiar with Angular, configuring your client will feel like working directly with Angular.

When we installed the client above, it created a [`client.gen.ts`](/docs/openapi/typescript/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

### `setConfig()`

This is the simpler approach. You can call the `setConfig()` method at the beginning of your application or anytime you need to update the client configuration. You can pass any `HttpRequest` configuration option to `setConfig()`, and even your own [`httpClient`](#custom-instance) implementation.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  baseUrl: 'https://example.com',
});
```

The disadvantage of this approach is that your code may call the `client` instance before it's configured for the first time. Depending on your use case, you might need to use the second approach.

### Runtime API

Since `client.gen.ts` is a generated file, we can't directly modify it. Instead, we can tell our configuration to use a custom file implementing the Runtime API. We do that by specifying the `runtimeConfigPath` option.

```js {7} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    {
      name: '@hey-api/client-angular',
      runtimeConfigPath: './src/hey-api.ts',
    },
  ],
};
```

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

```ts title="src/hey-api.ts"
import type { CreateClientConfig } from './client/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
  ...config,
  baseUrl: 'https://example.com',
});
```

With this approach, `client.gen.ts` will call `createClientConfig()` before initializing the `client` instance. If needed, you can still use `setConfig()` to update the client configuration later.

### `createClient()`

You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js title="src/index.ts"
import { createClient } from './client/client';

const myClient = createClient({
  baseUrl: 'https://example.com',
});
```

You can also pass this instance to any SDK function through the `client` option. This will override the default instance from `client.gen.ts`.

```js title="src/index.ts"
const response = await getFoo({
  client: myClient,
});
```

### SDKs

Alternatively, you can pass the client configuration options to each SDK function. This is useful if you don't want to create a client instance for one-off use cases.

```js title="src/index.ts"
const response = await getFoo({
  baseUrl: 'https://example.com', // <-- override default configuration
});
```

## `@Injectable`

If you prefer to use the [`@Injectable()`](https://angular.dev/api/core/Injectable) decorators, set the `asClass` option in your SDK plugin to `true`.

<Tabs>
  <TabItem label="example">
```ts title="src/foo.service.ts"
@Injectable({ providedIn: 'root' })
export class FooService {
  // class methods
}
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    '@hey-api/client-angular',
    {
      name: '@hey-api/sdk',
      asClass: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

## Interceptors

:::caution
This section is under construction. We appreciate your patience.
:::

## Auth

:::caution
This section is under construction. We appreciate your patience.
:::

## Build URL

If you need to access the compiled URL, you can use the `buildUrl()` method. It's loosely typed by default to accept almost any value; in practice, you will want to pass a type hint.

```ts title="src/index.ts"
type FooData = {
  path: {
    fooId: number;
  };
  query?: {
    bar?: string;
  };
  url: '/foo/{fooId}';
};

const url = client.buildUrl<FooData>({
  path: {
    fooId: 1,
  },
  query: {
    bar: 'baz',
  },
  url: '/foo/{fooId}',
});
console.log(url); // prints '/foo/1?bar=baz'
```

## Custom Instance

You can provide a custom `httpClient` instance. This is useful if you need to extend the default instance with extra functionality, or replace it altogether.

```js title="src/index.ts"
import { client } from 'client/client.gen';

client.setConfig({
  httpClient: inject(CustomHttpClient),
});
```

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom instance to be.

## Plugins

You might be also interested in the [Angular](/docs/openapi/typescript/plugins/angular) plugin.

<UserConfig package="openapi-ts" plugin="@hey-api/client-angular" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Community Contributing Building (`web/src/content/docs/docs/openapi/typescript/community/contributing/building.mdx`)

---
title: Building
description: Learn how to contribute to Hey API.
---

# Building

:::caution
This page is under construction. We appreciate your patience.
:::

## Prerequisites

You should have a working knowledge of [git](https://git-scm.com), [node](https://nodejs.org/en), and [pnpm](https://pnpm.io).

## Guidelines

Your [pull request](https://help.github.com/articles/using-pull-requests) must:

- address a single issue or add a single item of functionality
- contain a clean history of small, incremental, logically separate commits, with no merge commits
- use clear commit messages
- be possible to merge automatically

## Start `@hey-api/openapi-ts`

Run `pnpm --filter @hey-api/openapi-ts dev`.

---

### Web Src Content Docs Docs Openapi Typescript Community Contributing Developing (`web/src/content/docs/docs/openapi/typescript/community/contributing/developing.mdx`)

---
title: Developing
description: Learn how to contribute to Hey API.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';

# Developing

:::caution
This page is under construction. We appreciate your patience.
:::

## Working with Examples

The `examples` folder contains various integration examples that demonstrate how to use `@hey-api/openapi-ts` with different frameworks and libraries. These examples are kept in sync with the codebase through automated checks.

### Generating Example Code

When you make changes to the core packages that affect code generation, you need to regenerate the client code in all examples:

```sh
pnpm examples:update
```

This command will:

- Find all examples with an `openapi-ts` script
- Run the OpenAPI code generator for each example
- Update the generated client code in each example

### Checking Example Code

Before committing changes, ensure that all generated example code is up-to-date:

```sh
pnpm examples:check
```

This command will:

- Regenerate all example code
- Check if any files were modified
- Exit with an error if generated code is out of sync

This check is also run automatically in CI to ensure examples stay in sync with the main codebase.

### Example Workflow

1. Make changes to core packages
2. Build the packages: `pnpm build --filter="@hey-api/**"`
3. Regenerate examples: `pnpm examples:update`
4. Commit all changes including the updated generated code
5. The CI will verify that examples are in sync

:::tip
Think of generated example code as snapshot tests - they should always reflect the current state of the code generator.
:::

## Writing Changelogs

We use [Changesets](https://github.com/changesets/changesets) to manage releases and generate changelogs. When contributing changes, create a changeset to document your updates.

### Creating a Changeset

Run the following command to create a new changeset:

```sh
pnpm changeset
```

This will prompt you to:

1. Select the packages that were changed
2. Choose the semver bump type (major, minor, or patch)
3. Write a summary of your changes

### Changeset Format

Changesets use the following format:

```md title="example.changeset.md"
---
"@hey-api/openapi-ts": patch
---

**scope**: description of changes
```

**Scopes:**

- `cli`, `parser`, `output`, `config`, `input`, `internal`, `build`, `error` → Core section
- `plugin(name)` → Plugins section (e.g., `**plugin(zod)**:`, `**plugin(@hey-api/client-axios)**:`)
- Any other scope → Other section

**Breaking Changes:**

- Use `**BREAKING**:` prefix in the description to mark breaking changes
- For packages on v0.x (major version 0), minor bumps may include breaking changes. Use signal words like "removed", "renamed", or "changed signature" to indicate breaking changes.

### Examples

<Tabs>
  <TabItem label="Bug fix">
```md title="example.changeset.md"
---
"@hey-api/openapi-ts": patch
---

**parser**: fix explicit discriminator mapping
```
  </TabItem>
  <TabItem label="New feature">
```md title="example.changeset.md"
---
"@hey-api/openapi-ts": minor
---

**plugin(zod)**: handle guid string format
```
  </TabItem>
  <TabItem label="Breaking change">
```md title="example.changeset.md"
---
"@hey-api/openapi-ts": minor
---

**BREAKING**: removed deprecated `getClient()` function
```
  </TabItem>
  <TabItem label="Plugin change">
```md title="example.changeset.md"
---
"@hey-api/openapi-ts": patch
---

**plugin(@hey-api/client-fetch)**: improve error handling
```
  </TabItem>
</Tabs>

---

### Web Src Content Docs Docs Openapi Typescript Community Contributing Testing (`web/src/content/docs/docs/openapi/typescript/community/contributing/testing.mdx`)

---
title: Testing
description: Learn how to contribute to Hey API.
---

# Testing

:::caution
This page is under construction. We appreciate your patience.
:::

---

### Web Src Content Docs Docs Openapi Typescript Plugins Angular V19 (`web/src/content/docs/docs/openapi/typescript/plugins/angular/v19.mdx`)

---
title: Angular v19 Plugin
description: Generate Angular v19 HTTP requests and resources from OpenAPI with the Angular plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
custom:
  version: v19
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { maxScopp } from '@/data/people';

# Angular

<FeatureStatus status="beta" />

### About

[Angular](https://angular.dev/) is a web framework that empowers developers to build fast, reliable applications.

The Angular plugin for Hey API generates HTTP requests and resources from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

### Collaborators

<AuthorsList people={[maxScopp]} />

## Features

- Angular v19 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- generate HTTP requests
- generate HTTP resources
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@angular/common` to your plugins and you'll be ready to generate Angular artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@angular/common',
  ],
};
```

## Output

The Angular plugin will generate the following artifacts, depending on the input specification.

## Requests

A single function is generated for each endpoint. It returns an [`HttpRequest`](https://v19.angular.dev/api/common/http/HttpRequest) result.

<Tabs>
  <TabItem label="example">
```ts title="common.gen.ts"
export const addPetRequest = (options) =>
  client.requestOptions({
    method: 'POST',
    responseStyle: 'data',
    url: '/pet',
    ...options,
  });
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@angular/common',
      httpRequests: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

## Resources

A single function is generated for each endpoint. It returns a result from [`httpResource`](https://v19.angular.dev/api/common/http/httpResource) call.

<Tabs>
  <TabItem label="example">
```ts title="common.gen.ts"
export const addPetResource = (options) => httpResource(() => addPetRequest(options()));
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@angular/common',
      httpResources: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

<UserConfig package="openapi-ts" plugin="@angular/common" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Angular V20 (`web/src/content/docs/docs/openapi/typescript/plugins/angular/v20.mdx`)

---
title: Angular v20 Plugin
description: Generate Angular v20 HTTP requests and resources from OpenAPI with the Angular plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Angular
custom:
  version: v20
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { maxScopp } from '@/data/people';

# Angular

<FeatureStatus status="beta" />

### About

[Angular](https://angular.dev/) is a web framework that empowers developers to build fast, reliable applications.

The Angular plugin for Hey API generates HTTP requests and resources from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

### Collaborators

<AuthorsList people={[maxScopp]} />

## Features

- Angular v20 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- generate HTTP requests
- generate HTTP resources
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `@angular/common` to your plugins and you'll be ready to generate Angular artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@angular/common',
  ],
};
```

## Output

The Angular plugin will generate the following artifacts, depending on the input specification.

## Requests

A single function is generated for each endpoint. It returns an [`HttpRequest`](https://angular.dev/api/common/http/HttpRequest) result.

<Tabs>
  <TabItem label="example">
```ts title="common.gen.ts"
export const addPetRequest = (options) =>
  client.requestOptions({
    method: 'POST',
    responseStyle: 'data',
    url: '/pet',
    ...options,
  });
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@angular/common',
      httpRequests: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

## Resources

A single function is generated for each endpoint. It returns a result from [`httpResource`](https://angular.dev/api/common/http/httpResource) call.

<Tabs>
  <TabItem label="example">
```ts title="common.gen.ts"
export const addPetResource = (options) => httpResource(() => addPetRequest(options()));
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: '@angular/common',
      httpResources: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

<UserConfig package="openapi-ts" plugin="@angular/common" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Concepts Resolvers (`web/src/content/docs/docs/openapi/typescript/plugins/concepts/resolvers.mdx`)

---
title: Resolvers
description: Understand the concepts behind plugins.
---

import { Tabs, TabItem } from '@astrojs/starlight/components';

# Resolvers

Sometimes the default plugin behavior isn't what you need or expect. Resolvers let you patch plugins in a safe and performant way, without forking or reimplementing core logic.

Currently available for [TypeScript](/docs/openapi/typescript/plugins/typescript), [Valibot](/docs/openapi/typescript/plugins/valibot), and [Zod](/docs/openapi/typescript/plugins/zod).

## Examples

This page demonstrates resolvers through a few common scenarios.

1. [Handle arbitrary schema formats](#example-1)
2. [Validate high precision numbers](#example-2)
3. [Replace default base](#example-3)
4. [Create permissive enums](#example-4)

## Terminology

Before we look at examples, let's go through the resolvers API to help you understand how they work. Plugins that support resolvers expose them through the `$resolvers` option. Each resolver is a function that receives context and returns an implemented node (or patches existing ones).

The resolver context will usually contain:

- `$` - The node builder interface. Use it to build your custom logic.
- `nodes` - Parts of the plugin logic. You can use these to avoid reimplementing the functionality, or replace them with custom implementation.
- `plugin` - The plugin instance. You'll most likely use it to register new symbols.
- `symbols` - Frequently used symbols. These are effectively shorthands for commonly used `plugin.referenceSymbol()` calls.

Other fields may include the current schema or relevant utilities.

## Example 1

### Handle arbitrary schema formats

By default, the Valibot plugin may produce the following schemas for `date` and `date-time` strings.

```js title="valibot.gen.ts"
export const vDates = v.object({
  created: v.pipe(v.string(), v.isoDate()),
  modified: v.pipe(v.string(), v.isoTimestamp()),
});
```

We can override this behavior by patching the `nodes.format` function only for strings with `date` or `date-time` formats.

```js title="openapi-ts.config.ts"
{
  name: 'valibot',
  $resolvers: {
    string(ctx) {
      const { $, schema, symbols } = ctx;
      const { v } = symbols;
      if (schema.format === 'date' || schema.format === 'date-time') {
        ctx.nodes.format = () => $(v).attr('isoDateTime').call();
      }
    }
  }
}
```

This applies custom logic with surgical precision, without affecting the rest of the default behavior.

<Tabs>
  <TabItem label="after">
```js title="valibot.gen.ts"
export const vDates = v.object({
  created: v.pipe(v.string(), v.isoDateTime()),
  modified: v.pipe(v.string(), v.isoDateTime()),
});
```
  </TabItem>
  <TabItem label="before">
```js title="valibot.gen.ts"
export const vDates = v.object({
  created: v.pipe(v.string(), v.isoDate()),
  modified: v.pipe(v.string(), v.isoTimestamp()),
});
```
  </TabItem>
</Tabs>

## Example 2

### Validate high precision numbers

Let's say you're dealing with very large or unsafe numbers.

```js title="valibot.gen.ts"
export const vAmount = v.number();
```

In this case, you'll want to use a third-party library to validate your values. We can use big.js to validate all numbers by replacing the whole resolver.

```js title="openapi-ts.config.ts"
{
  name: 'valibot',
  $resolvers: {
    number(ctx) {
      const { $, plugin, symbols } = ctx;
      const { v } = symbols;
      const big = plugin.symbolOnce('Big', {
        external: 'big.js',
        importKind: 'default',
      });
      return $(v).attr('instance').call(big);
    }
  }
}
```

We're calling `plugin.symbolOnce()` to ensure we always use the same symbol reference.

<Tabs>
  <TabItem label="after">
```js title="valibot.gen.ts"
import Big from 'big.js';

export const vAmount = v.instance(Big);
```
  </TabItem>
  <TabItem label="before">
```js title="valibot.gen.ts"
export const vAmount = v.number();
```
  </TabItem>
</Tabs>

## Example 3

### Replace default base

You might want to replace the default base schema, e.g., `v.object()`.

```js title="valibot.gen.ts"
export const vUser = v.object({
  age: v.number(),
});
```

Let's say we want to interpret any schema without explicitly defined additional properties as a loose object.

```js title="openapi-ts.config.ts"
{
  name: 'valibot',
  $resolvers: {
    object(ctx) {
      const { $, symbols } = ctx;
      const { v } = symbols;
      const additional = ctx.nodes.additionalProperties(ctx);
      if (additional === undefined) {
        const shape = ctx.nodes.shape(ctx);
        ctx.nodes.base = () => $(v).attr('looseObject').call(shape);
      }
    }
  }
}
```

Above we demonstrate patching a node based on the result of another node.

<Tabs>
  <TabItem label="after">
```js title="valibot.gen.ts"
export const vUser = v.looseObject({
  age: v.number(),
});
```
  </TabItem>
  <TabItem label="before">
```js title="valibot.gen.ts"
export const vUser = v.object({
  age: v.number(),
});
```
  </TabItem>
</Tabs>

## Example 4

### Create permissive enums

By default, enum schemas are strict and will reject unknown values.

```js title="zod.gen.ts"
export const zStatus = z.enum(['active', 'inactive', 'pending']);
```

You might want to accept unknown enum values, for example when the API adds new values that haven't been added to the spec yet. You can use the enum resolver to create a permissive union.

```js title="openapi-ts.config.ts"
{
  name: 'zod',
  $resolvers: {
    enum(ctx) {
      const { $, symbols } = ctx;
      const { z } = symbols;
      const { enumMembers, literalSchemas } = ctx.nodes.items(ctx);

      if (!enumMembers.length || enumMembers.length !== literalSchemas.length) {
        return;
      }

      const enumSchema = $(z).attr('enum').call($.array(...enumMembers));
      return $(z).attr('union').call(
        $.array(enumSchema, $(z).attr('string').call())
      );
    }
  }
}
```

This resolver creates a union that accepts both the known enum values and any other string.

<Tabs>
  <TabItem label="after">
```js title="zod.gen.ts"
export const zStatus = z.union([z.enum(['active', 'inactive', 'pending']), z.string()]);
```
  </TabItem>
  <TabItem label="before">
```js title="zod.gen.ts"
export const zStatus = z.enum(['active', 'inactive', 'pending']);
```
  </TabItem>
</Tabs>

## Feedback

We welcome feedback on the Resolvers API. [Open a GitHub issue](https://github.com/hey-api/hey-api/issues) to request support for additional plugins.

---

### Web Src Content Docs Docs Openapi Typescript Plugins Orpc V1 (`web/src/content/docs/docs/openapi/typescript/plugins/orpc/v1.mdx`)

---
title: oRPC v1 Plugin
description: Generate oRPC v1 contracts from OpenAPI with the oRPC plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: oRPC
custom:
  version: v1
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { stephenZhou } from '@/data/people';

# oRPC

<FeatureStatus status="beta" />

### About

[oRPC](https://orpc.dev) combines RPC with OpenAPI, allowing you to define and call remote or local procedures through a type-safe API while adhering to the OpenAPI specification.

The oRPC plugin for Hey API generates contracts from your OpenAPI spec, fully compatible with all core features.

### Collaborators

<AuthorsList people={[stephenZhou]} />

## Features

- oRPC v1 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- generated contracts
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `orpc` to your plugins and you'll be ready to generate oRPC artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'orpc',
  ],
};
```

## Output

The oRPC plugin will generate the following artifacts, depending on the input specification.

## Contracts

Contracts are generated from all endpoints.

<Tabs>
  <TabItem label="example">
```ts title="orpc.gen.ts"
import { oc } from '@orpc/contract';

const addPet = oc.route({
  description: 'Add a new pet to the store.',
  inputStructure: 'detailed',
  method: 'POST',
  operationId: 'addPet',
  path: '/pet',
  summary: 'Add a new pet to the store.',
  tags: ['pet'],
});
```
  </TabItem>
  <TabItem label="config">
```js title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'orpc',
  ],
};
```
  </TabItem>
</Tabs>

### Validators

To enable schema validation, set `validator` to `zod` or one of the available [validator plugins](/docs/openapi/typescript/validators). This will automatically add the selected plugin with its default configuration.

For a more granular approach, manually add a validator plugin and set `validator` to the plugin name or `true` to automatically select a compatible plugin. Until you customize the validator plugin, both approaches will produce the same default output.

<Tabs>
  <TabItem label="example">
```ts {15,16} title="orpc.gen.ts"
import { oc } from '@orpc/contract';

import { vAddPetBody, vAddPetResponse } from './valibot.gen';

const addPet = oc
  .route({
    description: 'Add a new pet to the store.',
    inputStructure: 'detailed',
    method: 'POST',
    operationId: 'addPet',
    path: '/pet',
    summary: 'Add a new pet to the store.',
    tags: ['pet'],
  })
  .input(v.object({ body: vAddPetBody }))
  .output(vAddPetResponse);
```
  </TabItem>
  <TabItem label="config">
```js {8,11} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'orpc',
      validator: true, // or 'valibot'
    },
    {
      name: 'valibot', // customize (optional)
      // other options
    },
  ],
};
```
  </TabItem>
</Tabs>

You can choose to validate only inputs or outputs.

<Tabs>
  <TabItem label="inputs">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'orpc',
      validator: {
        input: 'zod',
      },
    },
  ],
};
```
  </TabItem>
  <TabItem label="outputs">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'orpc',
      validator: {
        output: 'zod',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

Learn more about available validators on the [Validators](/docs/openapi/typescript/validators) page.

<UserConfig package="openapi-ts" plugin="orpc" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Orpc V2 (`web/src/content/docs/docs/openapi/typescript/plugins/orpc/v2.mdx`)

---
title: oRPC v2 Plugin
description: Generate oRPC v2 contracts from OpenAPI with the oRPC plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: oRPC
custom:
  version: v2
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import AuthorsList from '@/components/AuthorsList.astro';
import Examples from '@/components/Examples.astro';
import FeatureStatus from '@/components/FeatureStatus.astro';
import UserConfig from '@/components/UserConfig.astro';
import { stephenZhou } from '@/data/people';

# oRPC

<FeatureStatus status="beta" />

### About

[oRPC](https://orpc.dev) combines RPC with OpenAPI, allowing you to define and call remote or local procedures through a type-safe API while adhering to the OpenAPI specification.

The oRPC plugin for Hey API generates contracts from your OpenAPI spec, fully compatible with all core features.

### Collaborators

<AuthorsList people={[stephenZhou]} />

## Features

- oRPC v2 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- generated contracts
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `orpc` to your plugins and you'll be ready to generate oRPC artifacts. 🎉

```js {6-9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'orpc',
      compatibilityVersion: '2',
    },
  ],
};
```

## Output

The oRPC plugin will generate the following artifacts, depending on the input specification.

## Contracts

Contracts are generated from all endpoints.

<Tabs>
  <TabItem label="example">
```ts title="orpc.gen.ts"
import { oc } from '@orpc/contract';
import { openapi } from '@orpc/openapi';

const addPet = oc.meta(
  openapi({
    description: 'Add a new pet to the store.',
    inputStructure: 'detailed',
    method: 'POST',
    operationId: 'addPet',
    path: '/pet',
    summary: 'Add a new pet to the store.',
    tags: ['pet'],
  }),
);
```
  </TabItem>
  <TabItem label="config">
```js title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'orpc',
      compatibilityVersion: '2',
    },
  ],
};
```
  </TabItem>
</Tabs>

### Query Styles

When generating oRPC v2 contracts, `queryStyles` metadata is inferred by default for OpenAPI serialization styles supported by oRPC, so arrays and delimited objects keep their original serialization behavior.

```ts title="orpc.gen.ts"
const getItems = oc.meta(
  openapi({
    inputStructure: 'detailed',
    method: 'GET',
    operationId: 'getItems',
    path: '/items',
    queryStyles: {
      ids: 'array',
      filters: 'comma-delimited-object',
      tags: 'comma-delimited-array',
    },
    tags: ['items'],
  }),
);
```

You can disable this metadata when you want oRPC's default bracket notation.

oRPC does not currently expose a `queryStyles` value for form-exploded objects, so those parameters use oRPC's default bracket notation.

```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      compatibilityVersion: '2',
      inferQueryStyles: false,
      name: 'orpc',
    },
  ],
};
```

### Validators

To enable schema validation, set `validator` to `zod` or one of the available [validator plugins](/docs/openapi/typescript/validators). This will automatically add the selected plugin with its default configuration.

For a more granular approach, manually add a validator plugin and set `validator` to the plugin name or `true` to automatically select a compatible plugin. Until you customize the validator plugin, both approaches will produce the same default output.

<Tabs>
  <TabItem label="example">
```ts {18,19} title="orpc.gen.ts"
import { oc } from '@orpc/contract';
import { openapi } from '@orpc/openapi';

import { vAddPetBody, vAddPetResponse } from './valibot.gen';

const addPet = oc
  .meta(
    openapi({
      description: 'Add a new pet to the store.',
      inputStructure: 'detailed',
      method: 'POST',
      operationId: 'addPet',
      path: '/pet',
      summary: 'Add a new pet to the store.',
      tags: ['pet'],
    }),
  )
  .input(v.object({ body: vAddPetBody }))
  .output(vAddPetResponse);
```
  </TabItem>
  <TabItem label="config">
```js {9,12} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      compatibilityVersion: '2',
      name: 'orpc',
      validator: true, // or 'valibot'
    },
    {
      name: 'valibot', // customize (optional)
      // other options
    },
  ],
};
```
  </TabItem>
</Tabs>

You can choose to validate only inputs or outputs.

<Tabs>
  <TabItem label="inputs">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'orpc',
      validator: {
        input: 'zod',
      },
    },
  ],
};
```
  </TabItem>
  <TabItem label="outputs">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'orpc',
      validator: {
        output: 'zod',
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

Learn more about available validators on the [Validators](/docs/openapi/typescript/validators) page.

<UserConfig package="openapi-ts" plugin="orpc" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Zod Mini (`web/src/content/docs/docs/openapi/typescript/plugins/zod/mini.mdx`)

---
title: Zod Mini Plugin
description: Generate Zod Mini schemas from OpenAPI with the Zod plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
custom:
  version: Mini
  versionSynonym: v4
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# Zod

### About

[Zod](https://zod.dev) is a TypeScript-first schema validation library with static type inference.

The Zod plugin for Hey API generates schemas from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

## Features

- Zod Mini support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- Zod schemas for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `zod` to your plugins and you'll be ready to generate Zod artifacts. 🎉

```js {6-9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
    },
  ],
};
```

### SDKs

Zod can validate or transform data directly in your SDK. Set `validator` or `transformer` to `true` on the SDK plugin to enable it.

<Tabs>
  <TabItem label="validator">
```js {10-13} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
    },
    {
      name: '@hey-api/sdk',
      validator: true,
    },
  ],
};
```
  </TabItem>
  <TabItem label="transformer">
```js {10-13} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
    },
    {
      name: '@hey-api/sdk',
      transformer: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

The SDK page covers [validators](/docs/openapi/typescript/plugins/sdk#validators) and [transformers](/docs/openapi/typescript/plugins/sdk#transformers) in more detail.

## Output

The Zod plugin will generate the following artifacts, depending on the input specification.

## Requests

A Zod schema is generated for every request layer of each endpoint.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zDeletePetHeaders = z.object({
  api_key: z.optional(z.string()),
});

const zDeletePetPath = z.object({
  petId: z.number(),
});

const zDeletePetQuery = z.object({
  additionalMetadata: z.string(),
});
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
      requests: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `requests` schemas using the `.name` and `.case` options.

## Responses

A single Zod schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zResponse = z.union([
  z.object({
    foo: z.optional(z.string()),
  }),
  z.object({
    bar: z.optional(z.number()),
  }),
]);
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
      responses: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `responses` schemas using the `.name` and `.case` options.

## Definitions

A Zod schema is generated for every reusable definition from your input.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zFoo = z.int();

const zBar = z.object({
  bar: z.optional(z.array(z.int())),
});
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
      definitions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `definitions` schemas using the `.name` and `.case` options.

## ISO Datetimes

By default, values without a timezone or with a timezone offset are not allowed in the `z.iso.datetime()` method.

### Timezone offsets

You can allow values with timezone offsets by setting `dates.offset` to `true`.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.iso.datetime({ offset: true });
```
  </TabItem>
  <TabItem label="config">
```js {10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
      dates: {
        offset: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Local times

You can allow values without a timezone by setting `dates.local` to `true`.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.iso.datetime({ local: true });
```
  </TabItem>
  <TabItem label="config">
```js {10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
      dates: {
        local: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Metadata

It's often useful to associate a schema with some additional [metadata](https://zod.dev/metadata) for documentation, code generation, AI structured outputs, form validation, and other purposes. You can set `metadata` to `true` to attach descriptions to schemas when available.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.string().register(z.globalRegistry, {
  description: 'Additional metadata',
});
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
      metadata: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

For more control over metadata, you can provide your own function. It receives the source `schema`, the target `node` object, and the `$` builder for populating metadata.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.string().register(z.globalRegistry, {
  hasTitle: true,
  createdAt: 1735732800000,
});
```
  </TabItem>
  <TabItem label="config">
```js {9-12} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
      metadata({ $, node, schema }) {
        node.prop('hasTitle', $.literal(Boolean(schema.title)));
        node.prop('createdAt', $.literal(Date.now()));
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Types

In addition to Zod schemas, you can generate schema-specific types. These can be generated for all schemas or for specific resources.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export type ResponseZodType = z.infer<typeof zResponse>;
```
  </TabItem>
  <TabItem label="config">
```js {10,14} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 'mini',
      types: {
        infer: false, // by default, no `z.infer` types
      },
      responses: {
        types: {
          infer: true, // `z.infer` types only for response schemas
        },
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for schema-specific `types` using the `.name` and `.case` options.

## Resolvers

You can further customize this plugin's behavior using [resolvers](/docs/openapi/typescript/plugins/concepts/resolvers).

<UserConfig package="openapi-ts" plugin="zod" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Zod V3 (`web/src/content/docs/docs/openapi/typescript/plugins/zod/v3.mdx`)

---
title: Zod v3 Plugin
description: Generate Zod v3 schemas from OpenAPI with the Zod plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
custom:
  version: v3
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# Zod

### About

[Zod](https://v3.zod.dev/) is a TypeScript-first schema validation library with static type inference.

The Zod plugin for Hey API generates schemas from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

## Features

- Zod v3 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- Zod schemas for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `zod` to your plugins and you'll be ready to generate Zod artifacts. 🎉

```js {6-9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
    },
  ],
};
```

### SDKs

Zod can validate or transform data directly in your SDK. Set `validator` or `transformer` to `true` on the SDK plugin to enable it.

<Tabs>
  <TabItem label="validator">
```js {10-13} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
    },
    {
      name: '@hey-api/sdk',
      validator: true,
    },
  ],
};
```
  </TabItem>
  <TabItem label="transformer">
```js {10-13} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
    },
    {
      name: '@hey-api/sdk',
      transformer: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

The SDK page covers [validators](/docs/openapi/typescript/plugins/sdk#validators) and [transformers](/docs/openapi/typescript/plugins/sdk#transformers) in more detail.

## Output

The Zod plugin will generate the following artifacts, depending on the input specification.

## Requests

A Zod schema is generated for every request layer of each endpoint.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zDeletePetHeaders = z.object({
  api_key: z.string().optional(),
});

const zDeletePetPath = z.object({
  petId: z.number(),
});

const zDeletePetQuery = z.object({
  additionalMetadata: z.string(),
});
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
      requests: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `requests` schemas using the `.name` and `.case` options.

## Responses

A single Zod schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zResponse = z.union([
  z.object({
    foo: z.string().optional(),
  }),
  z.object({
    bar: z.number().optional(),
  }),
]);
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
      responses: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `responses` schemas using the `.name` and `.case` options.

## Definitions

A Zod schema is generated for every reusable definition from your input.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zFoo = z.number().int();

const zBar = z.object({
  bar: z.array(z.number().int()).optional(),
});
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
      definitions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `definitions` schemas using the `.name` and `.case` options.

## ISO Datetimes

By default, values without a timezone or with a timezone offset are not allowed in the `z.string().datetime()` method.

### Timezone offsets

You can allow values with timezone offsets by setting `dates.offset` to `true`.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.string().datetime({ offset: true });
```
  </TabItem>
  <TabItem label="config">
```js {10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
      dates: {
        offset: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Local times

You can allow values without a timezone by setting `dates.local` to `true`.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.string().datetime({ local: true });
```
  </TabItem>
  <TabItem label="config">
```js {10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
      dates: {
        local: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Metadata

It's often useful to associate a schema with some additional [metadata](https://v3.zod.dev/?id=describe) for documentation, code generation, AI structured outputs, form validation, and other purposes. If this is your use case, you can set `metadata` to `true` to generate additional metadata about schemas.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.string().describe('Additional metadata');
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
      metadata: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

## Types

In addition to Zod schemas, you can generate schema-specific types. These can be generated for all schemas or for specific resources.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export type ResponseZodType = z.infer<typeof zResponse>;
```
  </TabItem>
  <TabItem label="config">
```js {10,14} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      compatibilityVersion: 3,
      types: {
        infer: false, // by default, no `z.infer` types
      },
      responses: {
        types: {
          infer: true, // `z.infer` types only for response schemas
        },
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for schema-specific `types` using the `.name` and `.case` options.

## Resolvers

You can further customize this plugin's behavior using [resolvers](/docs/openapi/typescript/plugins/concepts/resolvers).

<UserConfig package="openapi-ts" plugin="zod" />
<Examples />

---

### Web Src Content Docs Docs Openapi Typescript Plugins Zod V4 (`web/src/content/docs/docs/openapi/typescript/plugins/zod/v4.mdx`)

---
title: Zod v4 Plugin
description: Generate Zod v4 schemas from OpenAPI with the Zod plugin for openapi-ts. Fully compatible with validators, transformers, and all core features.
sidebar:
  label: Zod
custom:
  version: v4
---

import { Tabs, TabItem } from '@astrojs/starlight/components';
import Examples from '@/components/Examples.astro';
import UserConfig from '@/components/UserConfig.astro';

# Zod

### About

[Zod](https://zod.dev) is a TypeScript-first schema validation library with static type inference.

The Zod plugin for Hey API generates schemas from your OpenAPI spec, fully compatible with validators, transformers, and all core features.

## Features

- Zod v4 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- Zod schemas for requests, responses, and reusable definitions
- minimal learning curve thanks to extending the underlying technology

## Installation

In your [configuration](/docs/openapi/typescript/get-started), add `zod` to your plugins and you'll be ready to generate Zod artifacts. 🎉

```js {6} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'zod',
  ],
};
```

### SDKs

Zod can validate or transform data directly in your SDK. Set `validator` or `transformer` to `true` on the SDK plugin to enable it.

<Tabs>
  <TabItem label="validator">
```js {7-10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'zod',
    {
      name: '@hey-api/sdk',
      validator: true,
    },
  ],
};
```
  </TabItem>
  <TabItem label="transformer">
```js {7-10} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    'zod',
    {
      name: '@hey-api/sdk',
      transformer: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

The SDK page covers [validators](/docs/openapi/typescript/plugins/sdk#validators) and [transformers](/docs/openapi/typescript/plugins/sdk#transformers) in more detail.

## Output

The Zod plugin will generate the following artifacts, depending on the input specification.

## Requests

A Zod schema is generated for every request layer of each endpoint.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zDeletePetHeaders = z.object({
  api_key: z.string().optional(),
});

const zDeletePetPath = z.object({
  petId: z.number(),
});

const zDeletePetQuery = z.object({
  additionalMetadata: z.string(),
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      requests: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `requests` schemas using the `.name` and `.case` options.

## Responses

A single Zod schema is generated for all endpoint's responses. If the endpoint describes multiple responses, the generated schema is a union of all possible response shapes.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zResponse = z.union([
  z.object({
    foo: z.optional(z.string()),
  }),
  z.object({
    bar: z.optional(z.number()),
  }),
]);
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      responses: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `responses` schemas using the `.name` and `.case` options.

## Definitions

A Zod schema is generated for every reusable definition from your input.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
const zFoo = z.int();

const zBar = z.object({
  bar: z.optional(z.array(z.int())),
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      definitions: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for `definitions` schemas using the `.name` and `.case` options.

## ISO Datetimes

By default, values without a timezone or with a timezone offset are not allowed in the `z.iso.datetime()` method.

### Timezone offsets

You can allow values with timezone offsets by setting `dates.offset` to `true`.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.iso.datetime({ offset: true });
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      dates: {
        offset: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

### Local times

You can allow values without a timezone by setting `dates.local` to `true`.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.iso.datetime({ local: true });
```
  </TabItem>
  <TabItem label="config">
```js {9} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      dates: {
        local: true,
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Metadata

It's often useful to associate a schema with some additional [metadata](https://zod.dev/metadata) for documentation, code generation, AI structured outputs, form validation, and other purposes. You can set `metadata` to `true` to attach descriptions to schemas when available.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.string().register(z.globalRegistry, {
  description: 'Additional metadata',
});
```
  </TabItem>
  <TabItem label="config">
```js {8} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      metadata: true,
    },
  ],
};
```
  </TabItem>
</Tabs>

For more control over metadata, you can provide your own function. It receives the source `schema`, the target `node` object, and the `$` builder for populating metadata.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export const zFoo = z.string().register(z.globalRegistry, {
  hasTitle: true,
  createdAt: 1735732800000,
});
```
  </TabItem>
  <TabItem label="config">
```js {8-11} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      metadata({ $, node, schema }) {
        node.prop('hasTitle', $.literal(Boolean(schema.title)));
        node.prop('createdAt', $.literal(Date.now()));
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

## Types

In addition to Zod schemas, you can generate schema-specific types. These can be generated for all schemas or for specific resources.

<Tabs>
  <TabItem label="example">
```ts title="zod.gen.ts"
export type ResponseZodType = z.infer<typeof zResponse>;
```
  </TabItem>
  <TabItem label="config">
```js {9,13} title="openapi-ts.config.ts"
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    {
      name: 'zod',
      types: {
        infer: false, // by default, no `z.infer` types
      },
      responses: {
        types: {
          infer: true, // `z.infer` types only for response schemas
        },
      },
    },
  ],
};
```
  </TabItem>
</Tabs>

You can customize the naming and casing pattern for schema-specific `types` using the `.name` and `.case` options.

## Resolvers

You can further customize this plugin's behavior using [resolvers](/docs/openapi/typescript/plugins/concepts/resolvers).

<UserConfig package="openapi-ts" plugin="zod" />
<Examples />

---

--- METRICS ---
- Files Extracted: 111
- Estimated Token Budget: ~119442 tokens
- Canonical Reference: https://codewiki.google/github.com/hey-api/openapi-ts
