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, add @hey-api/sdk to your plugins and you'll be ready to generate SDK artifacts. 🎉
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.
import type { AddPetData } from './types.gen';
export const addPet = (options: Options<AddPetData>) => {
/** ... */
};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
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.
import type { AddPetData } from './types.gen';
export class Sdk extends HeyApiClient {
public addPet(options: Options<AddPetData>) {
/** ... */
}
}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
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.
import { client } from './client.gen';
import type { AddPetData, AddPetErrors, AddPetResponses } from './types.gen';
export class PetStore extends HeyApiClient {
/** ... */
}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
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.
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 {
/** ... */
}
}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
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.
import { client } from './client.gen';
client.setConfig({
auth() {
return '<token>';
},
});export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: [
// ...other plugins
{
auth: true,
name: '@hey-api/sdk',
},
],
};INFO
The SDK plugin currently supports only the bearer and basic auth schemes. Open an issue 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. 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.
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),
/** ... */
});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.
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',
},
},
],
};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 page.
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.
import { PetStore } from 'your-package';
await new PetStore().addPet();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
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.
import { PetStore } from '@petstore/client';
const client = new PetStore();
await client.addPet();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
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.
import { PetStore } from '@petstore/client';
const client = new PetStore({
apiKey: 'YOUR_API_KEY',
});
await client.addPet();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
If you re-export the generated SDK from your own module, you can adjust importName and importKind to match your actual import style.
import CatStore from '@petstore/client';
const client = new CatStore({
apiKey: 'YOUR_API_KEY',
});
await client.addPet();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 }) =>
$(node.name).call(
$.object().pretty().prop('apiKey', $.literal('YOUR_API_KEY')),
),
moduleName: '@petstore/client',
setupName: 'client',
},
name: '@hey-api/sdk',
operations: {
containerName: 'PetStore',
strategy: 'single',
},
},
],
};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.
import CatStore from '@petstore/client';
const client = new CatStore({
apiKey: 'YOUR_API_KEY',
});
await client.addPet({
petId: 1234,
}); 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 }) =>
$(node.name).call(
$.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
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 Mintlify or Scalar. To persist that specification, enable Source generation.
API
You can view the complete list of options in the UserConfig interface.
Examples
You can view live examples on StackBlitz.
Sponsors
Hey API is sponsor-funded. If you rely on Hey API in production, consider becoming a sponsor to accelerate the roadmap.
Gold

Best-in-class developer interfaces for your API.
stainless.comThe open source coding agent.
opencode.ai
