---
title: "SDK Plugin"
description: "Generate SDKs from OpenAPI with the SDK plugin for openapi-ts. Fully compatible with validators, transformers, and all core features."
url: "https://heyapi.dev/docs/openapi/typescript/plugins/sdk"
---

### About

[Section titled “About”](#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

[Section titled “Features”](#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

[Section titled “Installation”](#installation)

In your [configuration](https://heyapi.dev/openapi-ts/get-started), add `@hey-api/sdk` to your plugins and you’ll be ready to generate SDK artifacts. 🎉

openapi-ts.config.ts

```js
export default {
  input: 'hey-api/backend', // sign up at app.heyapi.dev
  output: 'src/client',
  plugins: [
    // ...other plugins
    '@hey-api/sdk',
  ],
};
```

## Output

[Section titled “Output”](#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

[Section titled “Flat”](#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`.

* example

  sdk.gen.ts

  ```ts
  import type { AddPetData } from './types.gen';


  export const addPet = (options: Options<AddPetData>) => {
    /** ... */
  };
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

## Instance

[Section titled “Instance”](#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`.

* example

  sdk.gen.ts

  ```ts
  import type { AddPetData } from './types.gen';


  export class Sdk extends HeyApiClient {
    public addPet(options: Options<AddPetData>) {
      /** ... */
    }
  }
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

### Name

[Section titled “Name”](#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`.

* example

  sdk.gen.ts

  ```ts
  import { client } from './client.gen';
  import type { AddPetData, AddPetErrors, AddPetResponses } from './types.gen';


  export class PetStore extends HeyApiClient {
    /** ... */
  }
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

### Structure

[Section titled “Structure”](#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.

* example

  sdk.gen.ts

  ```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 {
      /** ... */
    }
  }
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

## Auth

[Section titled “Auth”](#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.

* example

  sdk.gen.ts

  ```ts
  import { client } from './client.gen';


  client.setConfig({
    auth() {
      return '<token>';
    },
  });
  ```

* config

  openapi-ts.config.ts

  ```js
  export default {
    input: 'hey-api/backend', // sign up at app.heyapi.dev
    output: 'src/client',
    plugins: [
      // ...other plugins
      {
        auth: true,
        name: '@hey-api/sdk',
      },
    ],
  };
  ```

Note

The SDK plugin currently supports only the `bearer` and `basic` auth schemes. [Open an issue](https://github.com/hey-api/openapi-ts/issues) if you’d like support for additional mechanisms.

## Validators

[Section titled “Validators”](#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](https://heyapi.dev/openapi-ts/validators). This will implicitly add the selected plugin with default values.

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.

* example

  sdk.gen.ts

  ```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),
      /** ... */
    });
  ```

* config

  openapi-ts.config.ts

  ```js
  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
      },
    ],
  };
  ```

You can choose to validate only requests or responses.

* requests

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

* responses

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

Learn more about available validators on the [Validators](https://heyapi.dev/openapi-ts/validators) page.

## Code Examples

[Section titled “Code Examples”](#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.

* example

  ```ts
  import { PetStore } from 'your-package';


  await new PetStore().addPet();
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

### Module and Setup

[Section titled “Module and Setup”](#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.

* example

  ```ts
  import { PetStore } from '@petstore/client';


  const client = new PetStore();


  await client.addPet();
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

### Initialization

[Section titled “Initialization”](#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.

* example

  ```ts
  import { PetStore } from '@petstore/client';


  const client = new PetStore({
    apiKey: 'YOUR_API_KEY',
  });


  await client.addPet();
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

### Import Style

[Section titled “Import Style”](#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.

* example

  ```ts
  import CatStore from '@petstore/client';


  const client = new CatStore({
    apiKey: 'YOUR_API_KEY',
  });


  await client.addPet();
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

### Payload

[Section titled “Payload”](#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.

* example

  ```ts
  import CatStore from '@petstore/client';


  const client = new CatStore({
    apiKey: 'YOUR_API_KEY',
  });


  await client.addPet({
    petId: 1234,
  });
  ```

* config

  openapi-ts.config.ts

  ```js
  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',
        },
      },
    ],
  };
  ```

### Display

[Section titled “Display”](#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 such as [Scalar](https://kutt.to/skQUVd). To persist that specification, enable [Source](https://heyapi.dev/openapi-ts/configuration/output#source) generation.

## API

[Section titled “API”](#api)

You can view the complete list of options in the [UserConfig](https://github.com/hey-api/openapi-ts/blob/main/packages/openapi-ts/src/plugins/@hey-api/sdk/types.ts) interface.

## Examples

You can view live examples on [StackBlitz](https://stackblitz.com/orgs/github/hey-api/collections/openapi-ts-examples) or on [GitHub](https://github.com/hey-api/openapi-ts/tree/main/examples).
