Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 144 additions & 36 deletions docs/openapi-ts/clients/nuxt.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
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.
title: Nuxt Client
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why make these changes? Once we finalize this page, we should have a v4 page too, it's ambiguous which version it's compatible with otherwise

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Going forwards a major Nuxt release should still be backwards compatible with older modules. When Nuxt v5 releases Q4 25/Q1 26 the same module should work without any new changes. Since Nuxt 2 is EOL I don't think there'll be any confusion about using the module with it.

https://nuxt.com/docs/4.x/guide/going-further/modules#do-not-advertise-with-a-specific-nuxt-version

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work! I will still want to polish some of the wording in this copy, but overall I agree with the changes you've made/are making

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you 😄 docs isn't my strong suit

description: Generate a type-safe Nuxt client from OpenAPI with the Nuxt client for openapi-ts. Fully compatible with validators, transformers, and all core features.
---

<script setup lang="ts">
Expand All @@ -9,8 +9,7 @@ import VersionLabel from '@components/VersionLabel.vue';
</script>

<Heading>
<h1>Nuxt<span class="sr-only"> v3</span></h1>
<VersionLabel value="v3" />
<h1>Nuxt</h1>
</Heading>

::: warning
Expand All @@ -25,7 +24,6 @@ The Nuxt client for Hey API generates a type-safe client from your OpenAPI spec,

## Features

- Nuxt v3 support
- seamless integration with `@hey-api/openapi-ts` ecosystem
- type-safe response data and errors
- response data validation and transformation
Expand All @@ -36,7 +34,33 @@ The Nuxt client for Hey API generates a type-safe client from your OpenAPI spec,

## Installation

Start by adding `@hey-api/nuxt` to your dependencies.
### Automatic installation

Start by installing the `@hey-api/nuxt` Nuxt module.

::: code-group

```sh [npm]
npx nuxi module add @hey-api/nuxt
```

```sh [pnpm]
pnpx nuxi module add @hey-api/nuxt
```

```sh [yarn]
yarn dlx nuxi module @hey-api/nuxt
```

```sh [bun]
bunx nuxi module add @hey-api/nuxt
```

:::

### Manual installation

Add `@hey-api/nuxt` to your dependencies.

::: code-group

Expand All @@ -58,76 +82,135 @@ bun add @hey-api/nuxt

:::

In your [configuration](/openapi-ts/get-started), add `@hey-api/client-nuxt` to your plugins and you'll be ready to generate client artifacts. :tada:

::: code-group
Then, add it to the `modules` in your `nuxt.config.ts`:

```js [config]
export default {
input: 'hey-api/backend', // sign up at app.heyapi.dev
output: 'src/client',
plugins: ['@hey-api/client-nuxt'], // [!code ++]
};
```ts
export default defineNuxtConfig({
modules: [
'@hey-api/nuxt', // [!code ++]
],
});
```

```sh [cli]
npx @hey-api/openapi-ts \
-i hey-api/backend \
-o src/client \
-c @hey-api/client-nuxt # [!code ++]
## Getting started

Set an [input](/openapi-ts/configuration/input) within `nuxt.config.ts`, then start the Nuxt dev server.

```ts
export default defineNuxtConfig({
heyApi: {
config: {
input: './path/to/openapi.json', // [!code ++]
},
},
});
```

:::
The generated client can be accessed from `#hey-api/`.

```ts
import { client } from '#hey-api/client.gen';
```

::: tip

If you add `@hey-api/nuxt` to your Nuxt modules, this step is not needed.
The `@hey-api/client-nuxt` plugin is automatically added.

:::

### Options

### `alias`

Configure an [alias](https://nuxt.com/docs/api/nuxt-config#alias) to access the Hey API client.

Defaults to `#hey-api`

### `autoImports`

Adds the generated SDK items to auto imports. Defaults to `true`.

#### `config`

Configuration to pass to `@hey-api/openapi-ts`.

- [input](/openapi-ts/configuration/input)
- [output](/openapi-ts/configuration/output)
- Defaults to `.nuxt/client`
- [parser](/openapi-ts/configuration/parser)
- [plugins](/openapi-ts/plugins/transformers)

## 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 configured the Nuxt module above, it created a [`client.gen.ts`](/openapi-ts/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.

When we installed the client above, it created a [`client.gen.ts`](/openapi-ts/output#client) file. You will most likely want to configure the exported `client` instance. There are two ways to do that.
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.

### `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-fetch) implementation.

```js
import { client } from 'client/client.gen';
::: code-group

client.setConfig({
baseURL: 'https://example.com',
```vue [app.vue]
<script setup lang="ts">
import { client } from '#hey-api/client.gen';

await callOnce(async () => {
client.setConfig({
baseURL: 'https://example.com',
});
});
</script>
```

:::

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
::: code-group

```ts [nuxt]
export default defineNuxtConfig({
heyApi: {
config: {
input: 'hey-api/backend', // sign up at app.heyapi.dev
plugins: [
{
name: '@hey-api/client-nuxt',
runtimeConfigPath: './shared/lib/hey-api.ts', // [!code ++]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you sometimes use the ./shared/lib path in your examples?

Copy link
Author

@RihanArfan RihanArfan Sep 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The runtime config path should be within ./app or ./shared because of how Nuxt generates the tsconfigs for it's imports etc. so #hey-api/ will resolve to the generated client. If the file was directly in the project root, TS would throw errors since it can't resolve the import.

Originally I thought the generated Nuxt client could be used in both the frontend and server routes, so I figured the shared directory would be the best Nuxt folder for it. I just tested now and the generated client can't be used within server routes.
image

So based on this the Hey API docs should be recommending people put that file within ./app (anywhere). I guess the runtime config could reside in utils, but given that's an auto imported directory I think users using lib is better.

Suggested change
runtimeConfigPath: './shared/lib/hey-api.ts', // [!code ++]
runtimeConfigPath: './app/lib/hey-api.ts', // [!code ++]

We only need to mention it within the docs in the runtime config section, and it doesn't need to be added to other examples imo.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would need to change to make it work within server routes? Seems like an important issue, even if not directly related to this pull request

Copy link
Author

@RihanArfan RihanArfan Sep 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, it would make it so convenient for both building fully fullstack Nuxt, or BFFs (which are really popular with Nuxt).

I believe the issue is because the client has imports for Nuxt and Vue things which can't be used on Nitro server routes.

import {
useAsyncData,
useFetch,
useLazyAsyncData,
useLazyFetch,
} from 'nuxt/app';
import { reactive, ref, watch } from 'vue';

What I'd suggest is creating @hey-api/client-nitro @hey-api/client-ofetch (which basically a super simplified Nuxt client copy) and the Nuxt module can register these server imports with addServerImports(). As a standalone ofetch client, people using that outside of Nuxt/Nitro also benefit similar to how there's an Axios one.

On top of this you could create a separate Nitro module for standalone Nitro users (since it's a fantastic backend framework) which acts similarly to the Nuxt module

},
],
},
},
});
```

```js [standalone]
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', // [!code ++]
runtimeConfigPath: './shared/lib/hey-api.ts', // [!code ++]
},
],
};
```

:::

In our custom file, we need to export a `createClientConfig()` method. This function is a simple wrapper allowing us to override configuration values.

::: code-group

```ts [hey-api.ts]
import type { CreateClientConfig } from './client/client.gen';
import type { CreateClientConfig } from '#hey-api/client.gen';

export const createClientConfig: CreateClientConfig = (config) => ({
...config,
Expand All @@ -144,7 +227,7 @@ With this approach, `client.gen.ts` will call `createClientConfig()` before init
You can also create your own client instance. You can use it to manually send requests or point it to a different domain.

```js
import { createClient } from './client/client';
import { createClient } from '#hey-api/client';

const myClient = createClient({
baseURL: 'https://example.com',
Expand Down Expand Up @@ -180,7 +263,7 @@ If you omit `composable`, `$fetch` is used by default.
:::

```js
import { client } from 'client/client.gen';
import { client } from '#hey-api/client.gen';

const result = await client.get({
composable: '$fetch',
Expand All @@ -196,7 +279,7 @@ const result = await client.get({
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
import { client } from 'client/client.gen';
import { client } from '#hey-api/client.gen';

client.setConfig({
auth: () => '<my_token>', // [!code ++]
Expand All @@ -207,7 +290,7 @@ client.setConfig({
If you're not using SDKs or generating auth, using interceptors is a common approach to configuring auth for each request.

```js
import { client } from 'client/client.gen';
import { client } from '#hey-api/client.gen';

client.setConfig({
onRequest: ({ options }) => {
Expand Down Expand Up @@ -248,7 +331,7 @@ console.log(url); // prints '/foo/1?bar=baz'
You can implement your own `$fetch` method. This is useful if you need to extend the default `$fetch` method with extra functionality, or replace it altogether.

```js
import { client } from 'client/client.gen';
import { client } from '#hey-api/client.gen';

client.setConfig({
$fetch: () => {
Expand All @@ -259,6 +342,31 @@ client.setConfig({

You can use any of the approaches mentioned in [Configuration](#configuration), depending on how granular you want your custom method to be.

## Standalone usage

You can generate the Hey API Nuxt client via the CLI instead of the Nuxt module.

In your [configuration](/openapi-ts/get-started), add `@hey-api/client-nuxt` to your plugins and you'll be ready to generate client artifacts. :tada:

::: code-group

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

```sh [cli]
npx @hey-api/openapi-ts \
-i hey-api/backend \
-o src/client \
-c @hey-api/client-nuxt # [!code ++]
```

:::

## 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/client-nuxt/types.d.ts) interface.
Expand Down
Loading
Loading