# Output

## target

**Type:** `String`

Output path for generated files.

```ts
import { defineConfig } from 'orval';

export default defineConfig({
  petstore: {
    output: {
      target: 'src/petstore.ts',
    },
  },
});
```

## client

**Type:** `String | Function`
**Default:** `'axios-functions'`
**Options:** `angular`, `angular-query`, `axios`, `axios-functions`, `react-query`, `solid-start`, `solid-query`, `svelte-query`, `vue-query`, `pinia-colada`, `swr`, `zod`, `effect`, `hono`, `fetch`, `mcp`

See the [Pinia Colada guide](/docs/guides/pinia-colada) for generated Vue
queries, mutations, query keys, and options.

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'react-query',
    },
  },
});
```

You can also provide a function to create a custom client generator.

### axios client

The `axios` client generates a factory function with an optional axios instance parameter for dependency injection:

```typescript
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';

export const getPetsApi = (axiosInstance: AxiosInstance = axios) => ({
  listPets: (params?: ListPetsParams) =>
    axiosInstance.get<Pet[]>('/pets', { params }),
});
```

You can inject your own axios instance for testing or custom configuration:

```typescript
const customAxios = axios.create({ baseURL: 'https://api.example.com' });
const api = getPetsApi(customAxios);
```

The generated factory also exposes a `get<Operation>Url` helper for each
operation that does not use a custom mutator:

```typescript
const url = api.getListPetsUrl({ limit: 10 });
```

The helper returns the generated OpenAPI route with its query parameters
serialized by Axios. It uses the injected instance's Axios serialization
configuration, while ignoring that instance's runtime `baseURL`, default
request params, request options, and interceptors. The same helpers are emitted
for `axios-functions` and Axios-backed query clients.

Helpers are named `get<Operation>Url` (for example, `getListPetsUrl`) and
return a `string`. They accept the operation's path and query parameters, but
not Axios request options. Operations using a custom mutator do not emit a
helper because the mutator owns the runtime URL and serialization behavior.
Fetch output already has its own URL helper and is unchanged by this feature.

## httpClient

**Type:** `'fetch' | 'axios' | 'angular'`
**Default:** `'fetch'`

HTTP transport used by compatible generated clients. Use `fetch` or `axios` for
query clients, and `angular` for `angular` and `angular-query` output.

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'swr',
      httpClient: 'axios',
    },
  },
});
```

## schemas

**Type:** `String | Object | false`
**Default:** Same as `target`

Output path for generated model types. Set to `false` to disable separate schema file output.

### String form

```ts
export default defineConfig({
  petstore: {
    output: {
      schemas: './api/model',
    },
  },
});
```

### Object form

```ts
export default defineConfig({
  petstore: {
    output: {
      schemas: {
        path: './api/model',
        type: 'typescript', // 'typescript' | 'zod'
        routes: {
          default: 'models',
          enum: 'types',
        },
      },
    },
  },
});
```

| Property      | Type      | Description                                     |
| ------------- | --------- | ----------------------------------------------- |
| `path`        | `string`  | Filesystem path for schema output. A directory by default; in `mode: 'single'` it may point directly at the schema module file |
| `type`        | `string`  | `'typescript'` (default) or `'zod'` — optional |
| `importPath`  | `string`  | Optional package import specifier (see below)   |
| `splitByTags` | `boolean` | Organize schemas into per-tag subdirectories (default `false`, see below) |
| `routes`      | `object`  | Route enums separately from other schemas |
| `mode`        | `'split' \| 'single'` | Zod schema file layout (default `'split'`) |

`routes.default` is required and route values are relative directories under
`schemas.path`. `routes.enum` is optional; without it, enums use the default
route. Empty, absolute, parent-escaping, or equivalent route values are
rejected. Route comparison is case-insensitive so configurations remain
portable to case-insensitive file systems. Routes are supported for TypeScript
and Zod schemas; enums use `routes.enum` and all other schemas use
`routes.default`. Routes can be combined with `splitByTags`. They remain
incompatible with `operationSchemas`, mocks, and factory methods.

When different schema names produce the same generated file under the selected
naming convention, equivalent definitions are emitted once and imports are
redirected to the canonical schema. Different definitions are rejected with a
configuration error instead of being silently overwritten.

With `indexFiles: true`, Orval writes a barrel for each route that contains
schemas and a root `schemas/index.ts` barrel. With `indexFiles: false`,
generated imports point directly to the routed schema files.

For example, with `routes: { default: 'models', enum: 'types' }`:

```
schemas/
├── models/
│   ├── index.ts
│   └── pet.ts
├── types/
│   ├── index.ts
│   └── petStatus.ts
└── index.ts
```

When `splitByTags` is also enabled, tag directories are nested under their
route. Schemas used by multiple tags (or by no operation) are placed under
`<route>/shared`, for example `schemas/models/pets`,
`schemas/models/shared`, and `schemas/types/pets`.

### Single-file Zod schemas

Set `schemas.mode: 'single'` to write component and operation schemas into
`<schemas.path>/index.zod.ts`. The API client stays in its own output file and
imports the schemas and their derived TypeScript types from this module.

```ts
output: {
  target: './api/client.ts',
  client: 'react-query',
  httpClient: 'fetch',
  schemas: { path: './api/model', type: 'zod', mode: 'single' },
}
```

`path` names a directory by default, so the module is written as
`<schemas.path>/index.zod.ts`. In `mode: 'single'`, `path` may also point
directly at the output file, e.g.
`schemas: { path: './api/model.zod.ts', type: 'zod', mode: 'single' }`; a
directory path keeps the `index.zod.ts` behavior. The filename uses
`schemaFileExtension` (default `.zod.ts`). No additional barrel is generated,
regardless of `indexFiles`.
`importPath`, when provided, must resolve to the single module.
This mode cannot be combined with `splitByTags`, `routes`, `operationSchemas`,
mock generators, or `factoryMethods`.
Omitting `schemas.mode` preserves the existing split-file schema output.
`output.mode` independently controls how API client files are organized.

### importPath

When `importPath` is set, generated client files import schema types from
that package specifier instead of computing a relative filesystem path:

```ts
export default defineConfig({
  petstore: {
    output: {
      target: './libs/client/angular/src/lib/endpoints',
      schemas: {
        path: './libs/client/models/src/lib',
        type: 'typescript',
        importPath: '@acme/client/models',
      },
    },
  },
});
```

```ts
// Without importPath — computed relative path:
import type { Pet } from '../models/pet';

// With importPath: '@acme/client/models':
import type { Pet } from '@acme/client/models';
```

Schemas are still written to the filesystem `path` — only the generated
import statements change.

**Requirements when using `importPath`:**

- The target package must export the types at the specified import path.
- With `indexFiles: true` (recommended), all types are imported from the
  single `importPath` (e.g., `@acme/models`).
- With `indexFiles: false`, each schema is imported individually
  (e.g., `@acme/models/pet`). The package must support these subpath exports.
  For Zod schemas (`type: 'zod'`) the per-file suffix is `.zod`, so the
  package must also expose `./pet.zod` (e.g., `@acme/models/pet.zod`).
- If using faker schema factories
  (`mock: { generators: [{ type: 'faker', schemas: true }] }`),
  the package must also export `./index.faker`. When the package can't expose a
  sub-path (e.g. `importPath` resolves to a single barrel file via tsconfig
  path mappings), set [`schemasImportPath`](#schemasimportpath) on the faker
  generator to point faker factories at a separate import path.
- If using factory methods (`factoryMethods`), each schema is imported
  individually regardless of `indexFiles`.
- When `importPath` is set, the relative-path computation in
  `factoryMethods.outputDirectory` is bypassed: factories resolve imports
  against the package specifier rather than the on-disk factory output
  directory.
- Config normalization rejects invalid `importPath` values (empty, whitespace,
  relative, or absolute paths) before generation runs — see
  [Validation of `importPath`](#validation-of-importpath).

#### Validation of `importPath`

During config normalization, orval rejects the following `importPath` values
with a clear error message before generation runs:

- Empty string.
- Strings that are empty after trimming whitespace (e.g. `"   "`), or that
  contain leading/trailing whitespace around a valid-looking specifier.
- Relative specifiers starting with `./` or `../` (e.g. `./models`,
  `../models`).
- Absolute paths — POSIX (starting with `/`, e.g. `/abs/models`) or Windows
  (drive-letter like `C:\models`, or UNC like `\\server\share\models`).

### splitByTags

When `splitByTags` is `true`, schemas are organized into per-tag
subdirectories instead of a single flat directory. Schemas referenced by
only one tag go in that tag's directory; schemas referenced by multiple
tags (or not referenced by any operation) go in `shared`. If an operation has
multiple tags, Orval uses its first tag, matching the existing Orval routing
behavior. Works with any `output.mode` (`single`, `split`, `tags`, `tags-split`).

```ts
export default defineConfig({
  petstore: {
    output: {
      mode: 'tags-split',
      schemas: {
        path: './api/model',
        splitByTags: true,
      },
    },
  },
});
```

Result:

```
api/model/
├── shared/                ← schemas used by 2+ tags (or unreferenced)
│   ├── error.ts
│   └── pagination.ts
├── pets/                  ← schemas only used by "pets" operations
│   ├── pet.ts
│   ├── createPetsBody.ts
│   ├── listPetsParams.ts
│   └── index.ts
└── index.ts               ← root barrel re-exporting shared/ + tag dirs
```

Cross-tag imports from within a tag subdirectory resolve to the parent:

```ts
// pets/pet.ts
import type { Error } from '../shared/error';
```

**Requirements:**

- Works with any `output.mode` (`single`, `split`, `tags`, `tags-split`).
- Incompatible with `schemas.mode: 'single'`, which writes all Zod schemas
  into one file instead of per-tag directories.
- Can be combined with `schemas.routes`; tag directories are nested under the
  selected route, while shared schemas are nested under `<route>/shared`.
- Incompatible with `operationSchemas` — operation-derived types are placed
  within their tag directories automatically.
- Schema-to-tag mapping is transitive: if `Pet` imports `Dog` which imports
  `Dachshund`, all three land in the same directory.

## operationSchemas

**Type:** `String`

Separate path for operation-derived types (params, bodies, responses).

```ts
export default defineConfig({
  petstore: {
    output: {
      schemas: './api/model',
      operationSchemas: './api/model/params',
    },
  },
});
```

## fileExtension

**Type:** `String`
**Default:** `.ts`

Customize file extension for generated files:

```ts
export default defineConfig({
  petstore: {
    output: {
      mode: 'split',
      target: './gen/endpoints',
      schemas: './gen/model',
      fileExtension: '.gen.ts',
    },
  },
});
```

Result:

```
src/gen/
├── endpoints
│   └── swaggerPetstore.gen.ts
└── model
    ├── listPetsParams.ts
    └── pets.ts
```

## schemaFileExtension

**Type:** `String`
**Default:** `'.zod.ts'` when generating Zod schemas (`schemas: { type: 'zod' }` or `client: 'zod'` + [`generateReusableSchemas`](#generatereusableschemas)), otherwise the same as [`fileExtension`](#fileextension).

Override the file extension for schema artifacts only — without affecting the global `fileExtension` (which still drives client output, mock files, etc.). Useful when you want client files at one extension and schema files at another:

```ts
export default defineConfig({
  petstore: {
    output: {
      mode: 'split',
      client: 'zod',
      target: './gen/endpoints',
      schemas: './gen/model',
      fileExtension: '.ts',
      // Keep client files at .ts but emit reusable Zod schemas as .zod.ts:
      schemaFileExtension: '.zod.ts',
      override: { zod: { generateReusableSchemas: true } },
    },
  },
});
```

## namingConvention

**Type:** `'camelCase' | 'PascalCase' | 'snake_case' | 'kebab-case'`
**Default:** `'camelCase'`

Naming convention for generated **files**:

```ts
export default defineConfig({
  petstore: {
    output: {
      namingConvention: 'PascalCase',
      mode: 'split',
      target: './gen/endpoints',
    },
  },
});
```

## workspace

**Type:** `String`

Base folder for all generated files. Creates an `index.ts` with exports:

```ts
export default defineConfig({
  petstore: {
    output: {
      workspace: 'src/',
      target: './petstore.ts',
    },
  },
});
```

## mode

**Type:** `'single' | 'split' | 'tags' | 'tags-split' | 'tags-operations' | 'tags-operations-split'`
**Default:** `'single'`

### single

Everything in one file.

### split

Separate files for implementation, schemas, and mocks:

```
my-app/src/
├── petstore.schemas.ts
├── petstore.msw.ts
└── petstore.ts
```

### tags

One file per OpenAPI tag:

```
my-app/src/
├── pets.ts
└── petstore.schemas.ts
```

### tags-split

Folder per tag with split files:

```
my-app/src/
├── petstore.schemas.ts
└── pets/
    ├── petstore.msw.ts
    └── petstore.ts
```

When [`schemas`](#schemas) is configured, models go to a dedicated directory with per-file output. With [`indexFiles`](#indexfiles) enabled (the default), a barrel `index.ts` re-exports all schemas so service files import from a single path. With `indexFiles: false`, each schema is imported individually (e.g., `../models/pet`). All schemas — domain types, generic wrappers, and bound aliases — live in this single shared directory and are never duplicated per tag:

```
my-app/src/
├── models/
│   ├── index.ts
│   ├── pet.ts
│   ├── listResponse.ts
│   ├── pagination.ts
│   └── userListResponse.ts
├── pets/
│   └── pets.ts              ← imports from ../models
└── users/
    └── users.ts             ← imports from ../models
```

To organize schemas into per-tag subdirectories instead of a flat directory, use [`splitByTags`](#splitbytags):

```
my-app/src/
├── models/
│   ├── pagination.ts          ← shared schemas at root
│   ├── error.ts
│   ├── pets/
│   │   ├── pet.ts
│   │   ├── listPetsParams.ts
│   │   └── index.ts
│   ├── users/
│   │   ├── user.ts
│   │   ├── listUsersParams.ts
│   │   └── index.ts
│   └── index.ts               ← root barrel
├── pets/
│   └── pets.ts
└── users/
    └── users.ts
```

### tags-operations

Generate one implementation file per operation inside a directory for each
OpenAPI tag. When `indexFiles` is enabled (the default), a per-tag `index.ts`
re-exports the operation files:

```
my-app/src/
└── pets/
    ├── get-pet.ts
    ├── list-pets.ts
    └── index.ts
```

The operation file contains that operation's types and runtime implementation.
With `indexFiles: false`, import the operation files directly.
This mode is supported for the `react-query`, `svelte-query`, `vue-query`,
`swr`, and `fetch` clients.

### tags-operations-split

Generate one implementation file and one `.schemas.ts` file per operation,
nested under the operation's tag directory. When `indexFiles` is enabled (the
default), a per-tag `index.ts` re-exports both files:

```
my-app/src/
└── pets/
    ├── get-pet.ts
    ├── get-pet.schemas.ts
    ├── list-pets.ts
    ├── list-pets.schemas.ts
    └── index.ts
```

This mode uses the same supported clients as `tags-operations`. With
`indexFiles: false`, import the operation and schema files directly. Component
schemas referenced by an operation are emitted into that operation's schema
file; schemas configured through `output.schemas` continue to use that output
location.

## baseUrl

**Type:** `String | Object`
**Default:** `''`

```ts
export default defineConfig({
  petstore: {
    output: {
      baseUrl: 'https://api.example.com',
    },
  },
});
```

> **Note:**
> For the `angular` client, prefer
> [`override.angular.baseUrl`](#baseurl-1) when you need the base URL resolved
> through Angular's dependency injection (for example, per-API gateway routing
> or `TestBed` overrides) instead of baked into every generated route string.
> `baseUrl` and `override.angular.baseUrl` are mutually exclusive on the same
> output.

### runtime

**Type:** `String`

Embed a JavaScript expression into generated request URLs so the same build can call different hosts at runtime (for example with Docker images and environment variables). The value is emitted inside template literals in generated clients; only use trusted expressions from your configuration.
JavaScript expression used inside generated template literals for the request base URL. Set this to the expression only (for example `process.env.API_BASE_URL`), not including `` `${...}` ``; Orval wraps it for you.

```ts
export default defineConfig({
  petstore: {
    output: {
      baseUrl: {
        runtime: 'process.env.API_BASE_URL',
      },
    },
  },
});
```

#### imports

**Type:** `GeneratorImport[]`

Optional. When `runtime` references a symbol from another module, list the imports Orval should emit into generated clients. Paths are relative to the generated file, same idea as mutator imports. The `runtime` expression must be valid where the generated code runs (after those imports).

Use a default import:

```ts
export default defineConfig({
  petstore: {
    output: {
      baseUrl: {
        runtime: 'apiBase',
        imports: [{ name: 'apiBase', importPath: '../config/api' }],
      },
    },
  },
});
```

Or a named export used as an object (for example `import { env } from '../../env'` and `env.API_BASE_URL` in application code) — set `runtime` to that property access and import the object under `name`:

```ts
export default defineConfig({
  petstore: {
    output: {
      baseUrl: {
        runtime: 'env.API_BASE_URL',
        imports: [{ name: 'env', importPath: '../../env' }],
      },
    },
  },
});
```

Adjust `importPath` so it resolves from the generated client file to your module (the example assumes the client is nested deeper than `env.ts`).

### getBaseUrlFromSpecification

**Type:** `Boolean`

Read the base URL from the OpenAPI `servers` field instead of a fixed string. When `true`, Orval resolves it from the spec’s `servers` entry (optionally with `variables` and `index` below).

```ts
export default defineConfig({
  petstore: {
    output: {
      baseUrl: {
        getBaseUrlFromSpecification: true,
        variables: {
          environment: 'api.dev',
        },
      },
    },
  },
});
```

#### variables

**Type:** `Record<string, string>`

Values for variables used in server URL templates from the OpenAPI `servers` field.

#### index

**Type:** `Number`

Which `servers` entry to use (0-based) when multiple URLs are defined:

```ts
export default defineConfig({
  petstore: {
    output: {
      baseUrl: {
        getBaseUrlFromSpecification: true,
        index: 1, // Use second server URL
      },
    },
  },
});
```

## mock

**Type:** `Boolean | Object | Function`
**Default:** `false`

Configures one or more mock generators. The shorthand `mock: true` enables both MSW and Faker mock files with default options:

```ts
export default defineConfig({
  petstore: {
    output: {
      mock: true,
    },
  },
});
```

Each entry in `mock.generators` produces its own file (`<filename>.msw.ts`, `<filename>.faker.ts`, ...), unless `inline: true` keeps the code in the implementation file. Set `mock: false` (or omit it) to disable mock generation entirely.

### Mocks Options

```ts
export default defineConfig({
  petstore: {
    output: {
      mock: {
        indexMockFiles: true,
        generators: [
          {
            type: 'msw',
            delay: 1000,
            useExamples: false,
            generateEachHttpStatus: false,
            baseUrl: '/api',
            locale: 'en',
          },
          {
            type: 'faker',
            useExamples: false,
          },
        ],
      },
    },
  },
});
```

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `indexMockFiles` | `Boolean` | `false` | In `split` and `tags-split` modes, emit one root-level `index.<ext>.ts` file per generator entry that re-exports the mocks (e.g. `index.msw.ts`, `index.faker.ts`). In `tags-split` it re-exports the per-tag mocks; in `split` it re-exports the single mock file. Useful to keep mocks (e.g. MSW) in a dedicated barrel that production/model barrels never import. |
| `path` | `String` | `undefined` | Shared output directory for all mock files. Per-generator `path` values override this. In `single` and `tags` mode this only changes where the de-inlined mock files land; see `inline` to keep mock code in the implementation file instead. Ignored on function-form generators, which always fall back to the shared `path`. |
| `inline` | `Boolean` | `false` | In `single` and `tags` mode, mock code is written to separate `.msw.ts` / `.faker.ts` files next to the implementation file(s) by default, matching `split` and `tags-split`. Set to `true` to append mock code to the implementation file instead, matching the layout Orval used before this option existed. No effect in `split` or `tags-split`, which always write separate mock files. |
| `generators` | `Array<MockOptions \| Function>` | `[]` | One entry per output mock file. Each entry can be an object (`MockOptions`) or a custom `ClientMockBuilder` function. |

```ts
export default defineConfig({
  petstore: {
    output: {
      mock: {
        path: './src/api/mocks',
        generators: [
          { type: 'msw', path: './src/api/mocks/msw' },
          { type: 'faker' },
        ],
      },
    },
  },
});
```

### MSW generator (`type: 'msw'`)

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `type` | `'msw'` | required | Discriminator for MSW handler generation. |
| `path` | `String` | `undefined` | Output directory for this generator's mock files. Overrides the shared `mock.path` when set. In `single` and `tags` mode this only changes where the de-inlined mock file lands; see `mock.inline` to keep mock code in the implementation file instead. |
| `operationResponses` | `Boolean` | `true` | Emit `get<Op>ResponseMock` factories in the MSW output. Set to `false` to generate handlers only, response fallbacks become `undefined`. No effect when a Faker generator also emits the factories, the handlers then import them from the `.faker` file. Honored in `split` and `tags-split` modes. |
| `delay` | `Number \| Function \| false` | `false` | Response delay in ms. |
| `delayFunctionLazyExecute` | `Boolean` | `false` | Execute delay function at runtime instead of at build time. |
| `baseUrl` | `String` | `''` | Base URL for the generated MSW handlers. |
| `useExamples` | `Boolean` | `false` | Use OpenAPI examples to seed response values. |
| `generateEachHttpStatus` | `Boolean` | `false` | Generate response factories for every documented status code. |
| `locale` | `String` | `'en'` | Faker.js locale. |
| `preferredContentType` | `String` | `undefined` | Preferred content type when an operation lists more than one. |

### Faker generator (`type: 'faker'`)

The Faker generator emits the same `get<Op>ResponseMock` factories MSW would emit, but without any `msw` dependency or HTTP handler code. Useful for tests or stories that only need fake response data.

In `split` and `tags-split` modes, configuring Faker alongside MSW moves the `get<Op>ResponseMock` factories to the `.faker` file. The `.msw` file only contains the handlers and imports (and re-exports) the factories instead of duplicating them. If the Faker generator is configured with `operationResponses: false` it emits no factories, so there is nothing to move and the `.msw` file keeps them inline.

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `type` | `'faker'` | required | Discriminator for Faker-only output. |
| `path` | `String` | `undefined` | Output directory for this generator's mock files. Overrides the shared `mock.path` when set. In `single` and `tags` mode this only changes where the de-inlined mock file lands; see `mock.inline` to keep mock code in the implementation file instead. |
| `schemas` | `Boolean` | `false` | Emit a consolidated mock factory file (`get<SchemaName>Mock`) for every entry under `components/schemas`. |
| `schemasImportPath` | `String` | `undefined` | Package specifier for importing the schema-level faker factories emitted by `schemas: true` (e.g. `@acme/models/fakers`). When set, used verbatim instead of appending `/index.faker` to `schemas.importPath` — useful when the production barrel can't expose a sub-path export. Requires `schemas: true` and `schemas.importPath`. Only applies when `schemas: true` is set on the same generator. |
| `operationResponses` | `Boolean` | `true` | Emit per-operation response mock factories (the historical behavior). Set to `false` together with `schemas: true` to get only the consolidated schema factories. |
| `useExamples` | `Boolean` | `false` | Use OpenAPI examples to seed response values. |
| `generateEachHttpStatus` | `Boolean` | `false` | Generate response factories for every documented status code. |
| `locale` | `String` | `'en'` | Faker.js locale. |
| `preferredContentType` | `String` | `undefined` | Preferred content type when an operation lists more than one. |
| `arrayItems` | `Boolean` | `false` | Emit reusable mock factories for object-like array item schemas in operation responses. |

#### `schemasImportPath`

Only applies when `schemas: true` is set on the same faker generator (requires
both `schemas: true` and `schemas.importPath`). When `schemas.importPath`
resolves to a single barrel file (e.g. via tsconfig path mappings), appending
`/index.faker` produces an unresolvable sub-path. `schemasImportPath` lets you
point faker factories at a separate import path so you can expose them through a
dedicated barrel:

```ts
export default defineConfig({
  petstore: {
    output: {
      target: './libs/client/sdk/generated',
      schemas: {
        path: './libs/data-layer/sdk/generated',
        importPath: '@acme/data-layer/sdk',
      },
      mock: {
        path: './libs/client/sdk/mocks',
        generators: [
          {
            type: 'faker',
            schemas: true,
            schemasImportPath: '@acme/data-layer/sdk/fakers',
          },
        ],
      },
    },
  },
});
```

```ts
// Without schemasImportPath (default — joins importPath with /index.faker):
import { getPetMock } from '@acme/data-layer/sdk/index.faker'; // may not resolve

// With schemasImportPath: '@acme/data-layer/sdk/fakers':
import { getPetMock } from '@acme/data-layer/sdk/fakers';
```

## indexFiles

**Type:** `Boolean`
**Default:** `true`

Generate `index.ts` files for schemas.

## tagsSplitDeduplication

**Type:** `Boolean`
**Default:** `false`

In `tags-split` mode, when `tagsSplitDeduplication` is enabled and `workspace` is not set, shared infrastructure types (e.g. `HTTPStatusCode*` emitted by the fetch client) can be extracted into a single `common-types.ts` file. A shared-types file is generated only when there are shared types to extract; `indexFiles` independently controls whether a root `index.ts` barrel is generated.

Deduplication and [`indexFiles`](#indexfiles) control separate behaviors:

- Shared types that would otherwise be duplicated across per-tag files are collected and written once to `[commonTypesFileName].ts`
- Each per-tag file imports shared types from the common file instead of declaring them inline
- When `indexFiles: true`, a barrel `index.ts` is generated with named re-exports for public shared types plus `export *` re-exports for each per-tag implementation file

```ts
export default defineConfig({
  petstore: {
    output: {
      mode: 'tags-split',
      target: './src/api/endpoints.ts',
      schemas: './src/api/model',
      client: 'fetch',
      indexFiles: true,
      tagsSplitDeduplication: true,
    },
  },
});
```

Resulting structure:

```
src/api/
├── common-types.ts           ← shared types extracted once
├── index.ts                  ← barrel with named + wildcard re-exports
├── pets/
│   └── pets.ts               ← import type { ... } from '../common-types'
└── health/
    └── health.ts             ← import type { ... } from '../common-types'
```

When `tagsSplitDeduplication` is disabled (default), shared types are inlined
per tag. Shared-type extraction is only available when
`tagsSplitDeduplication` is enabled and `workspace` is not set. With that
condition satisfied, the shared types file can still be generated when
`indexFiles` is `false`, but the root barrel is not generated.

Shared-type extraction is suppressed when [`workspace`](#workspace) is set; the
workspace barrel handles aggregation instead.

## commonTypesFileName

**Type:** `String`
**Default:** `'common-types'`

The file name (without extension) used for the shared types file when [`tagsSplitDeduplication`](#tagssplitdeduplication) is enabled.

```ts
export default defineConfig({
  petstore: {
    output: {
      mode: 'tags-split',
      indexFiles: true,
      tagsSplitDeduplication: true,
      commonTypesFileName: 'shared',  // generates shared.ts
    },
  },
});
```

## docs

**Type:** `Boolean | Object`
**Default:** `false`

Generate API docs using [TypeDoc](https://typedoc.org/):

```ts
export default defineConfig({
  petstore: {
    output: {
      docs: true,
      // or with config
      docs: {
        configPath: './typedoc.config.mjs',
      },
    },
  },
});
```

## clean

**Type:** `Boolean | String[]`
**Default:** `false`

Remove files left over from previous runs before regenerating. What is removed depends on whether Orval owns the directory.

**`target` and `schemas` are wiped.** Every file in them is removed (`.d.ts` files are preserved) — not only files produced by Orval, but also any other file that happens to live there. These are the directories Orval asks you to keep hand-written files out of, so it takes them as its own.

**Configured mock directories are pruned.** Set [`mock.path`](#mock), or a mock generator's own `path`, to give mock files their own directory. You frequently keep hand-written code in that directory too — MSW's `browser.ts` and `server.ts`, fixtures, or a barrel. Orval removes only the files that it could have written there. The patterns are `**/*.msw<ext>` and `**/*.faker<ext>`. `<ext>` is your [`fileExtension`](#fileextension), or one of the usual source extensions: `.ts`, `.tsx`, `.mts`, `.cts`, `.js`, `.jsx`, `.mjs`, `.cjs`. Orval matches those extensions as well as your own. Thus a change from `.ts` to `.js` does not strand the mock files of the earlier runs.

The same rule applies when the mock directory is inside `target` or `schemas`. The wipe does not go into a mock directory. Orval prunes that directory instead.

Orval keeps all the files that these patterns do not match. But it also removes every empty directory below each directory that it cleans. This includes your own empty directories.

Without a mock path there is no separate mock directory: mock output lands beside the implementation files and is covered by the `target` rule above.

> **Warning:**
> Two limits apply to the prune patterns. A hand-written file with a name such as `handlers.msw.ts` or `fixtures.faker.ts` is removed, because Orval cannot tell it from its own output. And a compound `fileExtension` such as `.gen.ts` is matched only while you keep it configured. After you change it, remove the files of the earlier extension by hand.

When set to a `String[]`, the array entries are extra glob patterns appended to the deletion list for the `target` and `schemas` directories. They are **not** applied to mock directories — a positive glob there could delete hand-written files Orval never produced. Use negated globs (prefixed with `!`) to preserve specific files from removal.

```ts
export default defineConfig({
  petstore: {
    output: {
      // preserve `important.ts` when wiping `target` / `schemas`
      clean: ['!**/important.ts'],
    },
  },
});
```

For example, to keep a committed `swagger.json` next to the generated output:

```ts
export default defineConfig({
  petstore: {
    output: {
      target: './src/generated',
      clean: ['!**/swagger.json'],
    },
  },
});
```

> **Warning:**
> `clean` removes the entire contents of `target` and `schemas`, not just generated files. Do not point either directly at a package or library entrypoint root that holds files you need to keep (`package.json`, `ng-package.json`, `public-api.ts`, etc.). Place generated output in a dedicated subdirectory such as `./generated/` so those files are never touched.

Keep hand-written files (mutators, transformers, app code) outside the `target` and `schemas` directories for the same reason. You can share a configured mock directory with hand-written code, because Orval prunes that directory and does not wipe it. This stays true when the mock directory is inside `target` or `schemas`. But keep to the two limits above: do not give a hand-written file a mock file name, and do not rely on Orval to keep your empty directories.

> **Warning:**
> A directory configured by more than one project is cleaned by each of them before that project writes, so the last project to run wins and the earlier project's output is gone. This applies to `target`, `schemas`, and mock directories alike. Give each project its own output directories.

## formatter

**Type:** `'prettier' | 'biome' | 'oxfmt' | undefined`
**Default:** `undefined`

Format generated files with the specified formatter. Only one formatter can be used at a time.

```ts
export default defineConfig({
  petstore: {
    output: {
      formatter: 'prettier',
    },
  },
});
```

## headers

**Type:** `Boolean`
**Default:** `false`

Generate typed parameters for the HTTP request headers an operation declares in
the specification. When disabled, header parameters are omitted from the
generated function signatures.

This is unrelated to [`override.header`](#header), which controls the comment
block written at the top of each generated file.

```ts
export default defineConfig({
  petstore: {
    output: {
      headers: true,
    },
  },
});
```

## tsconfig

**Type:** `String | Object`

Custom TypeScript configuration path or inline config. When omitted, Orval looks
for the nearest `tsconfig.json` (or `jsconfig.json`).

```ts
export default defineConfig({
  petstore: {
    output: {
      tsconfig: './tsconfig.json',
      // or inline
      tsconfig: {
        compilerOptions: {
          moduleResolution: 'NodeNext',
        },
      },
    },
  },
});
```

Orval reads a small number of `compilerOptions` to shape the emitted imports —
`module` and `moduleResolution` (whether generated relative imports carry a
`.js` extension), `allowImportingTsExtensions`, `allowSyntheticDefaultImports`
and `esModuleInterop` (default vs namespace import form), `baseUrl`, and
`exactOptionalPropertyTypes`.

`target` is **not** one of them, and it does not need to be set for Orval's
sake. In particular, a [mutator](#mutator) is bundled internally only so its
exported function can be inspected for how many parameters it takes; that bundle
is discarded and never reaches your generated client, so it is parsed as modern
JavaScript regardless of the target your project compiles to. A mutator may
therefore use `import.meta`, top-level `await`, or any other syntax your own
toolchain supports.

## packageJson

**Type:** `String`

Path to your `package.json` (usually auto-detected).

---

## override

### transformer

**Type:** `String | Function`

Transform the generated output:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        transformer: 'src/yourfunction.js',
      },
    },
  },
});
```

### mutator

**Type:** `String | Object`

Custom HTTP client implementation:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        mutator: {
          path: './api/mutator/custom-instance.ts',
          name: 'customInstance',
        },
      },
    },
  },
});
```

Example implementation:

```ts
import Axios, { AxiosRequestConfig } from 'axios';

export const AXIOS_INSTANCE = Axios.create({ baseURL: '' });

export const customInstance = <T>(config: AxiosRequestConfig): Promise<T> => {
  return AXIOS_INSTANCE({ ...config }).then(({ data }) => data);
};

export type ErrorType<Error> = AxiosError<Error>;
export type BodyType<BodyData> = BodyData;
```

#### `inferred`

**Type:** `Boolean`

**Default:** `false`

When `true`, the generated fetch functions omit the `async` keyword and the `: Promise<T>` return type annotation. The return type is inferred from the custom mutator, allowing it to return sync values, Effect-style promises, or any other wrapper type.

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'fetch',
      override: {
        mutator: {
          path: './api/mutator/custom-instance.ts',
          name: 'customInstance',
          inferred: true,
        },
      },
    },
  },
});
```

### title

**Type:** `String | Function`

Customize the API service title (only for `axios` and `angular` clients):

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        title: (title) => `${title}Api`,
      },
    },
  },
});
```

### namingConvention (property keys)

**Type:** `Object`

Change naming convention for **property keys** (not files):

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        namingConvention: {
          enum: 'PascalCase', // camelCase, PascalCase, snake_case, kebab-case
        },
      },
    },
  },
});
```

### header

**Type:** `Boolean | Function`
**Default:** the built-in header function

Customize or disable the comment block written at the top of each generated
file. This is unrelated to [`output.headers`](#headers), which controls HTTP
request header parameters.

Pass `false` to omit the comment block, or a function to replace it. Passing
`true` produces the same output as omitting the option, since any value that is
neither `false` nor a function falls back to the built-in header.

The callback receives the OpenAPI [`Info Object`](https://spec.openapis.org/oas/v3.1.1#info-object) as `info`. `title` and `version` are required by the OpenAPI specification. `summary`, `description`, `termsOfService`, `contact`, and `license` are optional, so check them before using them. Specification extensions such as `x-*` may also be present. Return either one string, which is used verbatim, or an array of strings, which is rendered one line per string.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        header: (info) => [
          `Generated by Orval`,
          `Do not edit manually.`,
          ...(info.title ? [info.title] : []),
        ],
      },
    },
  },
});
```

---

## override.query

TanStack Query options:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        query: {
          useQuery: true,
          useSuspenseQuery: true,
          useMutation: true,
          useInfinite: true,
          useSuspenseInfiniteQuery: true,
          useInfiniteQueryParam: 'nextId',
          usePrefetch: true,
          useInvalidate: true,
          useSetQueryData: true,
          useGetQueryData: true,
          signal: true,
          runtimeValidation: true,
          options: {
            staleTime: 10000,
          },
        },
      },
    },
  },
});
```

### useQuery

**Type:** `Boolean`

**Default:** `true` for `GET` operations; `false` otherwise.

Generate `useQuery` hooks. When set explicitly, applies to **all
operations regardless of HTTP verb** — setting `useQuery: true` routes
`POST`, `PUT`, `PATCH`, and `DELETE` operations to `useQuery` hooks as
well. This is useful for APIs that use `POST` for read-style endpoints
(e.g. complex search bodies, GraphQL-style single-endpoint APIs).

Cache keys for non-`GET` operations are automatically namespaced by
HTTP verb to avoid collisions with `GET` operations on the same path
(e.g. `['POST', '/pets', body]`).

Set to `false` to suppress `useQuery` hook generation; pair with
`useMutation: true` (default for non-`GET`) if you want the request to
be wired up as a Mutation instead.

### useSuspenseQuery

**Type:** `Boolean`

**Default:** unset — opt-in.

Generate `useSuspenseQuery` hooks. When set globally, this only applies
to `GET` operations; per-operation overrides
(`override.operations.<id>.query.useSuspenseQuery`) bypass that
restriction for individual operations.

### useMutation

**Type:** `Boolean`

**Default:** `true` for non-`GET` operations; `false` otherwise.

Generate `useMutation` hooks. When set explicitly, applies to **all
operations regardless of HTTP verb** — setting `useMutation: true`
(globally or via `override.operations.<id>.query.useMutation`) routes
a `GET` operation to a `useMutation` hook as well. This is useful for
`GET` endpoints that you want to trigger imperatively rather than on
render.

Set to `false` to suppress Mutation hook generation; pair with
`useQuery: true` if you want non-`GET` operations to be generated as
Query hooks instead. When both `useQuery` and `useMutation` resolve to
`true` for the same operation, the Mutation hook wins for `GET` and the
Query hook wins for non-`GET`.

### useInfinite

**Type:** `Boolean`

**Default:** unset — opt-in.

Generate `useInfiniteQuery` hooks. When set globally, this only
applies to `GET` operations; per-operation overrides
(`override.operations.<id>.query.useInfinite`) bypass that
restriction for individual operations.

### useSuspenseInfiniteQuery

**Type:** `Boolean`

**Default:** unset — opt-in.

Generate `useSuspenseInfiniteQuery` hooks. When set globally, this
only applies to `GET` operations; per-operation overrides
(`override.operations.<id>.query.useSuspenseInfiniteQuery`) bypass
that restriction for individual operations.

### useInfiniteQueryParam

**Type:** `String | String[]`

Query parameter name for infinite queries. An operation only gets an infinite
hook when it declares the configured parameter.

Pass an array when a single spec paginates in more than one way. The names are
candidates in priority order and are resolved per operation: the first one the
operation actually declares becomes its page parameter, and an operation
matching none of them gets no infinite hook.

An `override.operations` entry replaces the global value entirely, so a single operation can opt into a different candidate
list.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        query: {
          useInfinite: true,
          useInfiniteQueryParam: ['page', 'cursor'],
        },
        operations: { 
          listBets: {
            useInfinite: true,
            useInfiniteQueryParam: "cursor.marker",
          }
        }
      },
    },
  },
});
```

### usePrefetch

**Type:** `Boolean`

Generate prefetch functions for SSR.

### useInvalidate

**Type:** `Boolean`

Generate query invalidation helpers.

### useSetQueryData

**Type:** `Boolean`

Generate type-safe helpers that update cached query data via [`setQueriesData`](https://tanstack.com/query/latest/docs/reference/QueryClient#queryclientsetqueriesdata).

Query keys are matched by prefix, so query params and body arguments are widened to accept `undefined`. Passing `undefined` updates every cached entry that shares the same path.

### useGetQueryData

**Type:** `Boolean`

Generate type-safe getQueryData helpers.

### useSkipToken

**Type:** `Boolean`
**Default:** `false`

Hold a query whose params are not resolved yet with [`skipToken`](https://tanstack.com/query/latest/docs/framework/react/guides/disabling-queries#typesafe-disabling-of-queries-using-skiptoken) instead of the generated `enabled` guard.

Unlike `enabled`, this also covers `refetch()`: no request is sent with an unresolved param, and the query rejects with `Missing queryFn` instead (TanStack also logs a console error in development). It leaves `enabled` free for the caller too — the caller's `...queryOptions` is spread last, so their own `enabled` would otherwise replace the generated param check.

React Query v5 only. Suspense queries are unaffected — TanStack excludes `SkipToken` from their `queryFn`.

### mutationInvalidates

**Type:** `Array`

Automatically invalidate or reset queries on mutation success (Angular Query, React Query, Svelte Query & Vue Query v5):

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        query: {
          useInvalidate: true,
          mutationInvalidates: [
            {
              onMutations: ['createPets'],
              invalidates: ['listPets'],
            },
            {
              onMutations: ['deletePet', 'updatePet'],
              invalidates: [
                'listPets',
                { query: 'showPetById', params: ['petId'], invalidationMode: 'reset' },
                { query: 'adminPets', file: './admin' },
              ],
            },
          ],
        },
      },
    },
  },
});
```

Each entry in `params` is either a **variable reference** (`string`) or a **literal value** (`{ literal: string }`):

| Syntax | Generated code |
|---|---|
| `params: ['petId']` | `getShowPetByIdQueryKey(variables.petId)` |
| `params: [{ literal: '@me' }]` | `getShowPetByIdQueryKey('@me')` |

Use `{ literal: "..." }` for fixed values like `"@me"` that are not taken from mutation variables:

```ts
mutationInvalidates: [
  {
    onMutations: ['updateProfile'],
    invalidates: [
      { query: 'getProfile', params: [{ literal: '@me' }] },
    ],
  },
],
```

When a user provides their own `onSuccess` callback, both the auto-invalidation and the user callback run — the generated `onSuccess` composes them together. To opt out of auto-invalidation at runtime, pass `skipInvalidation: true`:

```ts
// Default: invalidation + user callback both run
const deletePet = injectDeletePet({
  mutation: { onSuccess: () => showToast('Deleted!') },
});

// Skip auto-invalidation and handle it manually
const deletePet = injectDeletePet({
  mutation: {
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: getListPetsQueryKey() });
    },
  },
  skipInvalidation: true,
});
```

### signal

**Type:** `Boolean`

Include abort signal in queries.

### queryKey / queryOptions / mutationOptions

**Type:** `String | Object`

Custom query/mutation key or options functions.

When a `queryOptions` or `mutationOptions` mutator declares a third
parameter, orval passes operation identity so the mutator can branch on it
(for example, to attach per-operation metadata or invalidate by
`operationId`). The exact shape differs between the two:

- `queryOptions` mutator — `{ url, operationId, operationName }`
- `mutationOptions` mutator — `{ operationId, operationName }` (the `url`
  is supplied in the second parameter)

Each option takes a mutator, so point it at a file and an exported name:

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'react-query',
      override: {
        query: {
          queryKey: {
            path: './src/mutators/custom-query-key.ts',
            name: 'customQueryKey',
          },
          queryOptions: {
            path: './src/mutators/custom-query-options.ts',
            name: 'customQueryOptions',
          },
          mutationOptions: {
            path: './src/mutators/custom-mutation.ts',
            name: 'useCustomMutation',
          },
        },
      },
    },
  },
});
```

`queryKey` replaces the generated key factory. It receives the operation's
query properties and a context carrying the `url`:

```ts
export function customQueryKey(
  // The properties dictionary varies per operation (params, petId, ...), so
  // type it broadly if one mutator serves every endpoint.
  properties: Record<string, unknown>,
  context: { url: string },
) {
  return ['tenant-abc', context.url, properties] as const;
}
```

`queryOptions` wraps the options object passed to the generated hook. The
third parameter is the operation identity described above:

```ts
import type { QueryKey } from '@tanstack/react-query';

export function customQueryOptions<T extends { queryKey: QueryKey }>(
  options: T,
  _queryProperties: Record<string, unknown>,
  operation: { url: string; operationId: string; operationName: string },
): T & { queryKey: QueryKey } {
  return {
    ...options,
    queryKey: ['operation', operation.operationId, ...options.queryKey],
  };
}
```

`mutationOptions` works the same way for mutations, which is where branching
on `operationId` is most useful.

The mutator runs where the options object is built, inside the hook body, so
side effects belong in a callback rather than in the mutator itself. Calling
`invalidateQueries()` directly would fire on every render instead of after the
mutation succeeds:

```ts
import { type UseMutationOptions, useQueryClient } from '@tanstack/react-query';

export const useCustomMutation = <TData, TError, TVariables, TContext>(
  options: UseMutationOptions<TData, TError, TVariables, TContext>,
  _: { url: string },
  operation: { operationId: string; operationName: string },
) => {
  const queryClient = useQueryClient();
  if (operation.operationId !== 'deletePetById') return options;

  return {
    ...options,
    onSuccess: (...args: Parameters<NonNullable<typeof options.onSuccess>>) => {
      queryClient.invalidateQueries({ queryKey: ['/pets'] });
      // Keep whatever the caller already passed.
      return options.onSuccess?.(...args);
    },
  };
};
```

Because the mutator receives `operationId`, one file can serve every
operation and branch where the behaviour needs to differ, which is the usual
alternative to a per-operation configuration option.

#### Controlling the `use` / `get` prefix on options factories

Set `useHooks: false` on a `queryOptions` or `mutationOptions` mutator to
generate a `get<Operation>QueryOptions` or `get<Operation>MutationOptions`
factory instead of the default `use`-prefixed factory. This is useful when the
mutator does not call hooks and the factory is consumed outside a React
component, for example in a router loader or with `prefetchQuery` /
`ensureQueryData`.

```ts
export function customQueryOptions<T extends { queryKey: QueryKey }>(
  options: T,
): T {
  return options;
}
```

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'react-query',
      override: {
        query: {
          queryOptions: {
            path: './src/mutators/custom-query-options.ts',
            name: 'customQueryOptions',
            useHooks: false,
          },
          mutationOptions: {
            path: './src/mutators/custom-mutation-options.ts',
            name: 'customMutationOptions',
            useHooks: false,
          },
        },
      },
    },
  },
});
```

With this configuration, Orval generates `getPetstoreQueryOptions(...)` and
`getPetstoreMutationOptions(...)` instead of their `use`-prefixed variants.
The query options factory can then be used safely with `prefetchQuery` /
`ensureQueryData`:

```ts
export async function loader(queryClient: QueryClient) {
  return queryClient.ensureQueryData(getPetstoreQueryOptions());
}
```

> **Note:**
> The `use`/`get` prefix only affects the *name* of the exported options
> factory. The hook itself is still exported as `use<Operation>` and must
> be called from a React component.

### shouldExportMutatorHooks

**Type:** `Boolean`
**Default:** `true`

Export mutator hooks.

### shouldExportKeys

**Type:** `Boolean`
**Default:** `true`

Export the generated cache key getters. This covers query keys and mutation keys, the latter emitted next to the mutation options factory:

```ts
export const getShowPetByIdQueryKey = (petId: string) => {
  return ['pets', petId] as const;
};

export const getCreatePetsMutationKey = () => ['createPets'] as const;
```

### shouldFilterQueryKey

**Type:** `Boolean`
**Default:** `false`

Add `.filter(q => q !== undefined)` to the query key. If false, `as const` is added instead.
The filter can be adjusted with the `queryKeyFilter` option

When shouldFilterQueryKey is true:
```ts
export const getShowPetByIdQueryKey = (petId: string) => {
  return ['pets', petId].filter(q => q !== undefined);
};
```

When shouldFilterQueryKey is false:
```ts
export const getShowPetByIdQueryKey = (petId: string) => {
  return ['pets', petId] as const;
};
```

### queryKeyFilter

**Type:** `String`
**Default:** `'q => q !== undefined'`

Adjusts how the queryKey is filtered, when `shouldFilterQueryKey` is `true`. Default is `'q => q !== undefined'`, which will result
in it ending up beeing
```ts
.filter(q => q !== undefined)
```

One option could be to only make it filter out all falsy keys:
```ts
  shouldFilterQueryKey: true,
  queryKeyFilter: 'Boolean'
```

which would result in the generated code being
```ts
.filter(Boolean)
```

### shouldSplitQueryKey

**Type:** `Boolean`
**Default:** `false`

Generate query keys as arrays instead of strings.

### useOperationIdAsQueryKey

**Type:** `Boolean`
**Default:** `false`

Use operation ID instead of route path for query keys.

### version

**Type:** `Number`
**Default:** Detected from package.json

Force a specific version for generated hooks.

### runtimeValidation

**Type:** `boolean | { strategy: 'throw' | 'both' }`
**Default:** `false`

Enable Zod runtime validation for Angular query responses. Requires `schemas: { type: 'zod' }`. When enabled, responses are validated in the RxJS pipeline according to the configured strategy (`Schema.parse()` for the default `throw`). Skipped for primitive types and custom mutators.

A validated response is typed with the schema's `zod.output` alias (e.g. `PetsOutput`) instead of the input-typed schema name, since that is what the parse returns at runtime — relevant when the schema transforms values through `coerce`, `useDates`, defaults or `.transform()`. Operations using a custom mutator keep the schema (input) type: the mutator issues the request itself, so the generated parse never runs there.

The boolean form is preserved for backward compatibility: `true` ≡ `{ strategy: 'throw' }`. With `{ strategy: 'both' }` an invalid response is first logged through `console.error('[orval] <operation> response validation failed', error)` with the raw `ZodError`, then re-thrown — so the failure still surfaces through the client's native error channel while giving production visibility into contract drift.

---

## override.swr

SWR options:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        swr: {
          useInfinite: true,
          useSuspense: true,
          generateErrorTypes: false,
          swrOptions: {
            dedupingInterval: 10000,
          },
          swrMutationOptions: {
            revalidate: true,
          },
          swrInfiniteOptions: {
            initialSize: 10,
          },
        },
      },
    },
  },
});
```

### useInfinite

**Type:** `Boolean`

Generate `useSWRInfinite` hooks.

### useSWRMutationForGet

**Type:** `Boolean`

Generate `useSWRMutation` for GET requests.

### useSuspense

**Type:** `Boolean`
**Default:** `false`

Generate Suspense-compatible hooks.

### generateErrorTypes

**Type:** `Boolean`
**Default:** `false`

Generate custom error type aliases.

### swrOptions / swrMutationOptions / swrInfiniteOptions

**Type:** `Object`

Override SWR hook options.

---

## override.zod

Zod schema generation options:

For inline array responses, item schemas using `allOf`, `oneOf`, or `anyOf` are
also emitted as operation item schemas. Array items that are component
`$ref`s continue to use the component schema writer. See the [Zod guide](/docs/guides/zod#array-response-items) for an example.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        zod: {
          variant: 'mini',
          version: 4,
          strict: {
            response: true,
            query: true,
            param: true,
            header: true,
            body: true,
          },
          coerce: {
            query: ['string', 'number', 'boolean'],
          },
          generate: {
            param: true,
            body: true,
            response: true,
            query: true,
            header: true,
          },
          generateEachHttpStatus: true,
          useBrandedTypes: true,
          generateReusableSchemas: true,
          generateDiscriminatedUnion: true,
        },
      },
    },
  },
});
```

### variant

**Type:** `'classic' | 'mini'` — defaults to `'classic'`

Select the generated Zod API style.

| Value       | Output                                                                 |
| ----------- | ---------------------------------------------------------------------- |
| `'mini'`    | Import from `zod/mini` and emit Zod Mini's functional/check-based API. |
| `'classic'` | Import from `zod` and emit the regular chainable Zod API.              |

`'classic'` is the default to avoid changing existing projects. Prefer `'mini'` when startup time, memory usage, or bundle size matter.

Zod Mini requires Zod 4 output. If `variant: 'mini'` is used with `version: 3`, or with `version: 'auto'` resolving to Zod 3, Orval throws instead of generating invalid output.

### version

**Type:** `3 | 4 | 'auto'` — defaults to `'auto'`

Pin the Zod major version that generated output targets, so generation is deterministic instead of inferred from the installed `zod` package.

| Value    | Output                                                                          |
| -------- | ------------------------------------------------------------------------------- |
| `4`      | Always emit Zod 4 syntax (`z.strictObject`, `z.iso.datetime()`, `.meta()`, …).   |
| `3`      | Always emit Zod 3-compatible syntax (`.strict()`, `z.string().datetime()`, …).   |
| `'auto'` | Infer from the resolved `zod` version; fall back to Zod 4 when none is detected. |

Unlike most `override.zod` options, `version` is output-wide and cannot be set per operation or tag. See the [Zod guide](/docs/guides/zod#zod-version) for details.

### strict

**Type:** `Object`

Enable strict mode for schemas.

### coerce

**Type:** `Object`

Enable [coercion](https://zod.dev/api?id=coercion) for specified types.

### generate

**Type:** `Object`

Control which schemas are generated.

### preprocess

**Type:** `Object`

Add preprocess functions to schemas.

### params

**Type:** [`Mutator`](#mutator)

Inject a Zod `params` argument (e.g. `{ error: ... }`) into every generated validator. The referenced function is called once per validator at schema construction time and receives codegen-time context (operation, location, schema name, field path, validator name). Whatever it returns is passed as the trailing argument of the call.

Useful for i18n error keys, branded error messages, or any field-aware customisation that Zod's global error map cannot disambiguate on its own (because `issue.path` does not carry operation/schema identity).

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        zod: {
          params: { path: './zod-params.ts', name: 'zodParams' },
        },
      },
    },
  },
});
```

```ts
import type { ZodParamsContext } from 'orval';
import { i18n } from './i18n';

export const zodParams = (ctx: ZodParamsContext) => ({
  error: (issue: { input: unknown; path: PropertyKey[] }) =>
    i18n.t(
      `errors.${ctx.schemaName}.${ctx.fieldPath.join('.')}.${ctx.validator}`,
      { value: issue.input },
    ),
});
```

The `'schema'` location is used for shared component schemas emitted under [`generateReusableSchemas`](#generatereusableschemas). Component schemas have no single owning operation, so `operationId` is the empty string in that case — branch on `ctx.location === 'schema'` if your error keys need to fall back to a schema-only namespace.

Generated output (excerpt):

```ts
import { zodParams } from './zod-params';

export const CreateUserBody = zod.object({
  email: zod
    .string(zodParams({ operationId: 'createUser', location: 'body', schemaName: 'CreateUserBody', fieldPath: ['email'], validator: 'string' }))
    .email(zodParams({ operationId: 'createUser', location: 'body', schemaName: 'CreateUserBody', fieldPath: ['email'], validator: 'email' })),
});
```

Injection scope:

- Applied to base types (`string`, `number`, `boolean`, `bigint`, `date`, `integer`), constraints (`min`, `max`, `gt`, `lt`, `multipleOf`, `regex`, `length`), formats (`email`, `url`, `uuid`, `hostname`, `datetime`, `time`), and `literal`, `enum`, `instanceof`, `stringFormat`.
- Skipped on modifiers (`optional`, `nullable`, `nullish`, `default`, `describe`) and structural calls (`object`, `array`, `tuple`, `union`, `rest`, `passthrough`, `strict`).
- `fieldPath` only includes object property names, mirroring Zod's own `issue.path`. Array indices and tuple positions are not appended — the inner element of `{ tags: array<string> }` and a top-level `tags: string` both see `fieldPath: ['tags']`. Use the `validator` field to distinguish a container (`'array'`, `'tuple'`) from its element (`'string'`, `'number'`).

For static messages, return an object with a string `error`: `return { error: 'My message' }`. The function may return `undefined` to fall back to Zod defaults for a specific call.

> The `{ error }` shape is Zod v4-only — on v3 it is silently ignored and the default message is used. If your project supports both Zod v3 and v4, return `{ message: 'My message' }` instead, which works on both.

### dateTimeOptions / timeOptions

**Type:** `Object`

**Default (dateTimeOptions):** `{ offset: true }`

Configure Zod datetime/time validation options. `dateTimeOptions` defaults to `{ offset: true }` so generated schemas accept RFC3339 timestamps with timezone offsets (e.g. `2026-03-27T12:00:00+01:00`) — matching the OpenAPI `format: date-time` contract. Pass an explicit object to override (e.g. `{ offset: false }` or `{ offset: true, precision: 3 }`).

### useBrandedTypes

**Type:** `boolean`

**Default:** `false`

Append [`.brand()`](https://zod.dev/api?id=branded-types) to generated Zod schemas using the schema name as the brand identifier. For array request/response bodies, only the top-level array wrapper schema is branded — the exported `*Item` helper schema is not branded.

### generateReusableSchemas

**Type:** `boolean`

**Default:** `false`

Emit one reusable Zod schema per OpenAPI `#/components/schemas/*` `$ref` instead of inlining. The exported name is the last `$ref` segment with `namingConvention` applied. Other schemas and operation files reference the export by name (cycles are wrapped in `zod.lazy(() => Name)` only on the edges that close them).

Behavior:

- When `schemas:` is configured (string or `{ type: 'zod' }`) and `client: 'zod'` is set, the schemas directory holds reusable Zod schemas instead of TypeScript types. The schema files default to a `.zod.ts` extension; use [`schemaFileExtension`](#schemafileextension) to override it independently from the global [`fileExtension`](#fileextension) if you keep both TS types and reusable Zod schemas in the same directory.
- Operation files import the named exports — pure-`$ref` body/response wrappers (e.g. `PetCreateBody`) are skipped so consumers import the component schema directly.
- `$ref` siblings: `nullable`, `default`, `description` chain onto the named ref (e.g. `Pet.nullable().describe(...)`). `properties`, `example`, and other non-chainable siblings fall back to inlining at that one site.
- The `namingConvention` must produce valid JavaScript identifiers (`camelCase`, `PascalCase`, or `snake_case`). `kebab-case` is rejected with a clear error because it would emit dashed exports.
- **Trade-off — `readOnly` on shared component schemas:** without this flag, request bodies generated from `$ref` schemas strip `readOnly: true` properties so they don't appear in input validators. With this flag on, request and response endpoints share the same exported schema, so `readOnly` properties remain in body validators too. Either avoid `readOnly` on component schemas you share between requests and responses, or split into separate request/response schemas in the OpenAPI source.

### generateMeta

**Type:** `boolean`

**Default:** `false`

Attach registry metadata to generated **component** schemas via [`.meta()`](https://zod.dev/metadata) (zod v4 only): `id` is the schema name, plus `description` and `deprecated` when the OpenAPI schema provides them.

```ts
// override: { zod: { generateMeta: true } }
export const Pet = zod
  .object({ name: zod.string() })
  .meta({ id: 'Pet', description: 'A pet in the store', deprecated: true });
```

Behavior:

- Applies only to **component** schemas emitted as named exports (`schemas: { type: 'zod' }`, or `client: 'zod'` + [`generateReusableSchemas`](#generatereusableschemas)). Operation wrapper schemas are left untouched, so registry `id`s stay unique.
- `id` is always emitted; `description`/`deprecated` only when present. Property-level descriptions still use `.describe()`.
- **zod v3** has no `.meta()` — the option is a no-op there, and descriptions continue to emit via `.describe()`.
- The registry `id` makes [`z.toJSONSchema()`](https://zod.dev/json-schema) reference the schema as `#/$defs/<id>`, round-tripping the component structure.

### generateDiscriminatedUnion

**Type:** `boolean`

**Default:** `false`

Emit a `oneOf`/`anyOf` that carries an OpenAPI [`discriminator`](https://spec.openapis.org/oas/v3.1.0#discriminator-object) as [`zod.discriminatedUnion(key, [...])`](https://zod.dev/api?id=discriminated-unions) instead of a plain `zod.union([...])`. A discriminated union picks the branch by its discriminator value first, so validation errors point at the offending field (`type.name`) instead of collapsing into a single "no union member matched" at the union root.

```ts
// override: { zod: { generateDiscriminatedUnion: true } }
export const Pet = zod.discriminatedUnion('petType', [
  zod.object({ petType: zod.literal('cat'), meows: zod.boolean() }),
  zod.object({ petType: zod.literal('dog'), barks: zod.boolean() }),
]);
```

Behavior:

- **Opt-in.** Left `false`, unions are emitted exactly as before, so existing output is unchanged.
- **Safe fallback.** A discriminated union is emitted only when every branch can be represented as an object carrying a literal (`const`/`enum`) discriminator. If any branch is a non-object, a nested union, or lacks a literal discriminator, generation falls back to a plain `zod.union([...])` rather than emitting code that throws at construction.
- **Inheritance (`allOf`).** Branches composed with `allOf` are flattened into a single object so they remain valid discriminated-union options — this is the case that previously forced the feature to be reverted ([#2085](https://github.com/orval-labs/orval/issues/2085)). With [`generateReusableSchemas`](#generatereusableschemas), a branch that references an `allOf` schema stays a plain union (the referenced schema can't be guaranteed to be an object from the reference alone).
- Works with both Zod v3 (>= 3.20) and v4, and with the [`mini`](#variant) variant.

### exactOptional

**Type:** `boolean`

**Default:** `false`

Emit optional object properties with `.exactOptional()` (classic) / `zod.exactOptional()` (mini) instead of `.optional()`, so consumers compiling with [`exactOptionalPropertyTypes`](https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes) infer `{ x?: T }` rather than `{ x?: T | undefined }`.

```ts
// override: { zod: { exactOptional: true } }
export const Pet = zod.object({ name: zod.string().exactOptional() });
```

Behavior:

- **Opt-in.** Left `false`, optional properties emit `.optional()` as before, so existing output is unchanged.
- **zod v4 only.** zod v3 has no `.exactOptional()`, so the option is a no-op there and `.optional()` is emitted.
- Applies to optional properties in both the classic and [`mini`](#variant) variants.

### generateCompanionTypes

**Type:** `boolean`

**Default:** `false`

Follow every generated per-operation `export const` with a `zod.input`/[`zod.output`](https://zod.dev/basics?id=inferring-types) type alias pair, so consumers can import a TypeScript type instead of writing one by hand.

```ts
// override: { zod: { generateCompanionTypes: true } }
export const CreatePetsBody = zod.object({ name: zod.string() });

export type CreatePetsBody = zod.input<typeof CreatePetsBody>;
export type CreatePetsBodyOutput = zod.output<typeof CreatePetsBody>;
```

Behavior:

- **Opt-in.** Left `false`, output is unchanged.
- Applies to per-operation schemas — `Params`, `QueryParams`, `Header`, `Body`, and `Response` — including the Hono `*.zod.ts` output, which goes through the same generator. Component schemas emitted under [`generateReusableSchemas`](#generatereusableschemas) already carry this pair unconditionally and are unaffected by this flag.
- For an array request/response body, both the `*Item` schema and the array wrapper get their own pair.
- Uses `zod.input`, not `z.infer` (an alias of `zod.output`): request-side schemas commonly carry `.default()`, `coerce`, or `.transform()`, where the pre-parse (`input`) and post-parse (`output`) shapes differ.
- With [`useBrandedTypes`](#usebrandedtypes), the clean `zod.input` alias stays unbranded — `.brand()` only affects the output type — so the brand shows up on the `...Output` alias.
- Helper value consts (`...Max`, `...Min`, `...RegExp`, `...Default`) are plain values, not schemas, and never get a companion pair.
- Supported as a per-operation or per-tag override alongside `strict`, `generate`, `coerce`, `preprocess`, `params`, and `useBrandedTypes` (see [Scoping options per operation or tag](/docs/guides/zod#scoping-options-per-operation-or-tag)).

---

## override.effect

Effect schema generation options:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        effect: {
          strict: {
            response: true,
            query: true,
            param: true,
            header: true,
            body: true,
          },
          generate: {
            param: true,
            body: true,
            response: true,
            query: true,
            header: true,
          },
          generateEachHttpStatus: true,
          useBrandedTypes: true,
        },
      },
    },
  },
});
```

### strict

**Type:** `Object`

Enable strict mode for schemas.

### generate

**Type:** `Object`

Control which schemas are generated.

### useBrandedTypes

**Type:** `boolean`

**Default:** `false`

Append `S.brand()` to generated Effect schemas using the schema name as the brand identifier. For array request/response bodies, only the top-level array wrapper schema is branded.

### exactOptional

**Type:** `boolean`

**Default:** `false`

Emit optional Struct properties with `S.optionalWith(schema, { exact: true })` instead of `S.optional(schema)`, so consumers compiling with [`exactOptionalPropertyTypes`](https://www.typescriptlang.org/tsconfig/#exactOptionalPropertyTypes) infer `{ x?: T }` rather than `{ x?: T | undefined }`.

---

## override.angular

Angular client options:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        angular: {
          provideIn: 'root', // 'root' | 'any' | '' | false
          retrievalClient: 'httpClient',
          runtimeValidation: true,
          httpResource: {
            debugName: 'getPetByIdResource',
          },
        },
      },
    },
  },
});
```

> **Note:**
> `override.angular` is reserved for Angular generator settings such as retrieval
> mode, DI scope, and runtime validation. Angular-only request pipeline overrides
> like [`override.paramsFilter`](#paramsfilter) still live on `override` so they
> can also be applied consistently via `override.operations[...]` and
> `override.tags[...]`, alongside `mutator` and `paramsSerializer`.

### provideIn

**Type:** `'root' | 'any' | boolean`
**Default:** `'root'`

Controls the Angular `@Injectable({ providedIn })` scope for generated service
classes.

> **Note:**
> `provideIn` affects generated service classes only. `httpResource`
> functions are plain exports, not injectables.

### retrievalClient

**Type:** `'httpClient' | 'httpResource' | 'both'`
**Default:** `'httpClient'`

Controls how **retrieval-style** Angular operations are generated.

- `httpClient`: keep retrievals as injectable services backed by Angular `HttpClient`
- `httpResource`: generate signal-first retrieval functions using Angular
  `httpResource`
- `both`: keep `HttpClient` service methods and emit retrieval resources in a
  sibling `*.resource.ts` file

Mutation-style operations still use generated `HttpClient` service methods by
default unless a per-operation override changes the classification.

### client

**Type:** `'httpClient' | 'httpResource' | 'both'`

Backward-compatible alias for `retrievalClient`. Prefer
`override.angular.retrievalClient` in new configs to make the retrieval-only
scope clearer.

### runtimeValidation

**Type:** `boolean | { strategy: 'throw' | 'both' }`
**Default:** `false`

Enable Zod runtime validation for Angular output. Requires
`schemas: { type: 'zod' }`. This option is opt-in for backward compatibility.

- For generated `HttpClient` services, eligible JSON body responses are
  validated against the schema in the RxJS pipeline.
- For generated `httpResource` functions, eligible JSON resources are validated
  against the schema via the resource's `parse` option.

The exact mechanism depends on the strategy: `throw` parses directly (e.g.
`Schema.parse()`), while `both` validates through a safe-parse wrapper so it can
log before re-throwing.

The boolean form is preserved for backward compatibility: `true` ≡
`{ strategy: 'throw' }`. With `{ strategy: 'both' }` an invalid response is first
logged through `console.error('[orval] <operation> response validation failed', error)`
with the raw `ZodError`, then re-thrown — so the failure still surfaces through
the client's native error channel (RxJS error / `resource.error()` signal) while
giving production visibility into contract drift.

Validation is skipped for primitive types, non-JSON responses, and custom
mutator paths that bypass the generated validation flow. For Angular
`HttpClient`, `observe: 'events' | 'response'` responses are still validated by
cloning the response and validating its JSON body.

### queryObjectSerialization

**Type:** `'spec' | 'legacy'`
**Default:** `'spec'`

Controls how query parameters whose declared schema is a plain object are
serialized when no `paramsSerializer`/`paramsFilter` is configured for the
operation. See the
[Object query parameters guide](/docs/guides/angular#object-query-parameters-style--explode)
for the full explanation and a worked example.

- `spec` (default): honor the OpenAPI parameter's `style`/`explode` — `form` +
  `explode: true` (the OpenAPI default) spreads the object's properties as
  top-level query params, `form` + `explode: false` joins them into a single
  comma-separated value, and `deepObject` emits bracketed `name[prop]` keys.
- `legacy`: restore the pre-#3705 behavior of silently dropping object-typed
  query params from the generated request.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        angular: {
          queryObjectSerialization: 'legacy',
        },
      },
    },
  },
});
```

Like `retrievalClient`/`runtimeValidation`, this can be set globally, per-tag
(`override.tags[...].angular`), or per-operation
(`override.operations[...].angular`). It has no effect when a
`paramsSerializer` or `paramsFilter` is configured — those remain in full
control of the raw value. See
[issue #3705](https://github.com/orval-labs/orval/issues/3705).

### httpResource

**Type:** `Object`

Options forwarded into generated `httpResource` calls.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        angular: {
          retrievalClient: 'httpResource',
          httpResource: {
            defaultValue: { id: 'fallback' },
            debugName: 'getPetByIdResource',
            injector: 'inject(Injector)',
            equal: '(a, b) => a?.id === b?.id',
          },
        },
      },
    },
  },
});
```

#### defaultValue

**Type:** `unknown`

Initial value exposed while the resource is idle/loading. When configured,
generated overloads return `HttpResourceRef<T>` instead of
`HttpResourceRef<T | undefined>`.

#### debugName

**Type:** `String`

Name shown in Angular DevTools.

#### injector

**Type:** `String`

Raw expression passed to `HttpResourceOptions.injector`.

#### equal

**Type:** `String`

Raw expression passed to `HttpResourceOptions.equal`.

### baseUrl

**Type:** `Object`

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        angular: {
          baseUrl: {
            apiId: 'petstore',
          },
        },
      },
    },
  },
});
```

Opt-in: compose this output's runtime base URL through Angular dependency
injection (an `InjectionToken`) instead of baking a static prefix into every
generated route string. See the
[Angular guide](/docs/guides/angular#di-based-base-url-composition-multiple-apis--gateway-routing)
for the full precedence chain, the generated artifacts, and a multi-API
gateway-routing example.

> **Note:**
> `angular`-client only. Setting `baseUrl` on any other client logs a warning
> and has no effect.

#### apiId

**Type:** `String` (required)

Explicit, stable identifier for this API. Must match
`/^[A-Za-z][A-Za-z0-9_-]*$/`; Orval throws a config-time error otherwise.
`apiId` is **never** derived from the specification's `info.title` or the
target file name — it drives every generated identifier, so it needs to stay
stable across regenerations:

| Generated identifier | Derivation |
|---|---|
| `<API_ID>_SERVER_URL` | Embedded fallback URL constant |
| `<API_ID>_BASE_URL_RESOLVER` | `InjectionToken` for the runtime resolver hook |
| `<API_ID>_BASE_URL` | `InjectionToken` for the composed, normalized base URL |
| `<Api>BaseUrlResolverContext` | Resolver context type (`{ apiId, serverUrl }`) |
| `<Api>BaseUrlResolver` | Resolver function type |
| `provide<Api>BaseUrl(baseUrl)` | Directly provides the base URL, bypassing the resolver |
| `provide<Api>BaseUrlResolver(resolver)` | Provides a custom resolver |

`<API_ID>` is `apiId` upper-snake-cased (e.g. `petstore` → `PETSTORE`);
`<Api>` is `apiId` PascalCased (e.g. `petstore` → `Petstore`).

#### index

**Type:** `Number`
**Default:** `0`

Which entry of the specification's `servers` array to embed as the default
fallback URL, same semantics as [`baseUrl.index`](#index) on the top-level
`baseUrl` option.

#### variables

**Type:** `Record<string, string>`

Values for any `{variable}` placeholders in the selected server URL.

#### Error and warning behavior

- **Missing/invalid `apiId`** — throws
  `` `override.angular.baseUrl.apiId` must be a non-empty string matching /^[A-Za-z][A-Za-z0-9_-]*$/ `` at config-normalization time.
- **Combined with `output.baseUrl`** — throws: `` `override.angular.baseUrl` cannot be combined with the top-level `output.baseUrl` ``.
  Remove `output.baseUrl` from the output; the token's fallback already reads
  the specification's `servers` field, and a runtime override belongs in a
  provided resolver.
- **Set on a non-`angular` client** — logs a warning and is otherwise ignored.
- **Set under `override.operations[...].angular` or `override.tags[...].angular`**
  — logs a warning and is ignored. `baseUrl` is an output-level concern
  configured once via `override.angular.baseUrl`, not per operation or tag.

---

## override.hono

Hono server options:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        hono: {
          handlers: 'src/handlers',
          handlerGenerationStrategy: 'smart',
          validatorOutputPath: 'src/validator.ts',
          compositeRoute: 'src/routes.ts',
        },
      },
    },
  },
});
```

### handlers

**Type:** `String`

Changes output path for Hono handlers.

### handlerGenerationStrategy

**Type:** `'smart' | 'skip' | 'full'`

**Default:** `'smart'`

Controls how an **existing** handler file is treated when you re-run orval. A
file that does not exist yet is always generated fresh.

- `smart` (default) — non-destructively reconcile only the parts orval owns: its
  own imports (names, module paths, casing) and the `zValidator(...)` arguments,
  and append handlers for new operations. Your custom imports, middleware,
  handler bodies, and top-level helpers are preserved. Requires the optional
  `typescript` peer dependency (see note below); if it is absent, smart falls
  back to `skip` with a warning.
- `skip` — leave an existing handler file byte-for-byte unchanged. New operations
  still get fresh files (in `split` mode).
- `full` — rebuild the file header, imports, and validator chain from the spec,
  splicing back only each handler body. **Destructive:** custom imports,
  middleware, and top-level helpers are dropped. Use only if you keep handlers
  minimal and want maximal sync with the spec.

> **Note:**
> `smart` and `full` use the TypeScript compiler API to parse existing handler
> files. `typescript` is an optional peer dependency — virtually every orval
> project already has it, so nothing extra is installed.

> **Warning:**
> If `output.clean` is enabled and the handlers directory lives under the output
> target directory, handler files are deleted before generation runs, which
> defeats `smart`/`skip` preservation. Disable `clean` (or scope it) when
> relying on handler preservation.

### validatorOutputPath

**Type:** `String`

Changes the validator output path.

### compositeRoute

**Type:** `String`

Generate a combined routes file.

---

## override.mcp

MCP server options:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        mcp: {
          server: {
            path: './custom-server.ts',
            name: 'customServer',
          },
          handler: {
            path: './custom-handler.ts',
            name: 'customHandler',
          },
        },
      },
    },
  },
});
```

### server

**Type:** `String | Object`

Custom server function to use instead of the default `StdioServerTransport`. When set, the generated `server.ts` calls the function with `createMcpServer`.

Example implementation using `@hono/mcp`:

```ts
import type {
  McpServer,
  RegisteredTool,
} from '@modelcontextprotocol/sdk/server/mcp.js';
import { StreamableHTTPTransport } from '@hono/mcp';
import { Hono } from 'hono';

export const customServer = (
  createMcpServer: (options?: RequestInit) => {
    server: McpServer;
    tools: Record<string, RegisteredTool>;
  },
) => {
  const app = new Hono();
  const { server } = createMcpServer();
  const transport = new StreamableHTTPTransport();

  app.all('/mcp', async (c) => {
    if (!server.isConnected()) {
      await server.connect(transport);
    }
    return transport.handleRequest(c);
  });

  Bun.serve({ fetch: app.fetch, port: Number(process.env.PORT ?? 3000) });
};
```

### handler

**Type:** `Object`

Custom handler function that replaces the default response shaping and error mapping of every generated handler. When set, each handler binds the tool arguments to a `fetcher` and calls your function with it and the tool call context. The return value is used as the tool result as is.

```ts
import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol.js';
import type {
  CallToolResult,
  ServerNotification,
  ServerRequest,
} from '@modelcontextprotocol/sdk/types.js';

export const customHandler = async (
  fetcher: (
    overrides?: RequestInit,
  ) => Promise<{ status: number; data: unknown; headers: Headers }>,
  ctx?: RequestHandlerExtra<ServerRequest, ServerNotification>,
): Promise<CallToolResult> => {
  const res = await fetcher();

  if (res.status >= 400) {
    return {
      content: [{ type: 'text', text: JSON.stringify(res.data ?? null) }],
      isError: true,
    };
  }

  return {
    content: [{ type: 'text', text: JSON.stringify(res.data ?? null) }],
    structuredContent: res.data as Record<string, unknown>,
  };
};
```

See the [MCP guide](/docs/guides/mcp#custom-handler) for details on `fetcher` and `ctx`.

---

## override.axios

Axios client options:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        axios: {
          includeHttpResponseReturnType: true,
        },
      },
    },
  },
});
```

### includeHttpResponseReturnType

**Type:** `Boolean`
**Default:** `false`

Include the HTTP status in the return type and correlate it with the response
data type. For example, an operation with a JSON `200` response and an empty
`204` response returns a union that narrows `data` to the JSON body or `void`
based on `status`.

The built-in Axios client normalizes spec-declared empty responses to
`undefined`. With a custom `mutator`, the option changes the generated type but
not the runtime value because the mutator issues the request itself. The
mutator must return a complete Axios response with the same status-correlated
shape.

---

## override.fetch

Fetch client options:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        fetch: {
          includeHttpResponseReturnType: false,
          forceSuccessResponse: true,
        },
      },
    },
  },
});
```

### includeHttpResponseReturnType

**Type:** `Boolean`
**Default:** `true`

Include HTTP status in return type. Set to `false` to return data directly. When
an exact response status and a matching wildcard are both declared, the exact
status takes precedence in the generated type. For example, `200` and `2XX`
produce `status: 200` and `status: Exclude<HTTPStatusCode2xx, 200>`.

### forceSuccessResponse

**Type:** `Boolean`
**Default:** `false`

Throw on error responses instead of returning them.

### serializeResponseHeaders

**Type:** `Boolean`
**Default:** `false`

Return response `headers` as a plain `Record<string, string>` instead of a `Headers` instance. Enable it when a response is cached across a serialization boundary — a `Headers` instance in `dehydrate()` state makes a Next.js Server Component fail with `Only plain objects can be passed to Client Components from Server Components`. Requires `includeHttpResponseReturnType` (the default).

Header names are lowercased and repeated headers are joined with `, `. `set-cookie` is dropped, because a dehydrated cache is embedded in the RSC payload and upstream session cookies must not travel with it. Only `headers` is converted: `blob` responses still return a `Blob`, and `application/x-ndjson` responses still return the raw `Response` under `stream`.

With a custom `mutator` the option changes the generated type but not the runtime value, because the mutator issues the request itself. The mutator must return headers that already match the declared shape — as it must for `includeHttpResponseReturnType` today.

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'react-query',
      httpClient: 'fetch',
      override: {
        fetch: {
          serializeResponseHeaders: true,
        },
      },
    },
  },
});
```

### jsonReviver

**Type:** `String | Object`

Custom JSON reviver function (useful for date parsing).

### runtimeValidation

**Type:** `boolean | { strategy: 'throw' | 'both' }`
**Default:** `false`

Enable Zod runtime validation for fetch client responses. Requires `schemas: { type: 'zod' }`. When enabled, JSON responses are validated according to the configured strategy (`Schema.parse()` for the default `throw`) before being returned.

The boolean form is preserved for backward compatibility: `true` ≡ `{ strategy: 'throw' }`. With `{ strategy: 'both' }` an invalid response is first logged through `console.error('[orval] <operation> response validation failed', error)` with the raw `ZodError`, then re-thrown (rejecting the returned promise) — giving production visibility into contract drift while still failing fast.

A validated response is typed with the schema's `zod.output` alias (e.g. `PetsOutput`) instead of the input-typed schema name, since that is what the parse returns at runtime — relevant when the schema transforms values through `coerce`, `useDates`, defaults or `.transform()`. Operations using a custom mutator keep the schema (input) type: the mutator issues the request itself, so the generated parse never runs there.

### arrayFormat

**Type:** `'repeat' | 'brackets' | 'comma'`

Controls how array query parameters are serialized when the OpenAPI spec does not explicitly set `explode` on a parameter. The spec's own `explode` property always takes precedence.

| Value | Output |
|-------|--------|
| `repeat` | `?tags=a&tags=b` |
| `brackets` | `?tags[]=a&tags[]=b` |
| `comma` | `?tags=a%2Cb` |

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'fetch',
      override: {
        fetch: {
          arrayFormat: 'repeat',
        },
      },
    },
  },
});
```

For full control over serialization (including custom encoding, nested objects, etc.) use [`override.paramsSerializer`](#paramsserializer) instead.

### useRuntimeFetcher

**Type:** `Boolean`
**Default:** `false`

Allow injecting a custom `fetch` function at runtime. When enabled, generated request functions accept an optional `fetchFn` parameter and call `(fetchFn ?? fetch)(...)` instead of the global `fetch(...)`. For query client hooks, a `fetcher` field is added to the options type. Has no effect on operations that use a custom mutator.

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'react-query', // also works with 'fetch', 'vue-query', 'svelte-query'
      httpClient: 'fetch',
      override: {
        fetch: {
          useRuntimeFetcher: true,
        },
      },
    },
  },
});
```

**Generated output example**

```ts
// Request function — gains a fetchFn parameter
export const listPets = async (
  params: ListPetsParams,
  options?: RequestInit,
  fetchFn?: typeof globalThis.fetch,
): Promise<listPetsResponse> => {
  const res = await (fetchFn ?? fetch)(getListPetsUrl(params), {
    ...options,
    method: 'GET',
  });
  // ...
};

// Query hook — gains a fetcher field in options
export const useListPets = (
  params: ListPetsParams,
  options?: {
    query?: UseQueryOptions<...>;
    fetch?: RequestInit;
    fetcher?: typeof globalThis.fetch;
  },
) => { ... };
```

**Usage — SSR with request-scoped fetch**

```ts
// SvelteKit — +page.ts
export const load = async ({ fetch }) => {
  const queryClient = new QueryClient();
  await prefetchListPetsQuery(queryClient, params, { fetcher: fetch });
  return { queryClient };
};
```

---

## Runtime validation support matrix

`runtimeValidation` support differs by client family and mutator usage:

| Client | Config key | Status | Notes |
|--------|------------|--------|-------|
| `angular` | `override.angular.runtimeValidation` | ✅ | Validates JSON body responses via `Schema.parse()`; skips primitive/`void`, `observe: 'events'/'response'`, and custom mutator paths |
| `angular-query` | `override.query.runtimeValidation` | ✅ | Validates eligible responses via `Schema.parse()` in RxJS pipeline; types them as the schema's `zod.output` alias; skips primitive/`void` and custom mutator paths |
| `fetch` | `override.fetch.runtimeValidation` | ✅ | Validates JSON responses via `Schema.parse()`; types them as the schema's `zod.output` alias; skips primitive/`void`, ndjson and custom mutator paths |
| any client with custom mutator | varies | ⚠️ | Runtime validation may be bypassed depending on mutator path and signature (see [#2858](https://github.com/orval-labs/orval/issues/2858)). For the `fetch` client, [`override.includeZodSchemaInArguments`](#includezodschemainarguments) passes the schema to the mutator so it can validate the response itself |

Runtime validation is **disabled by default** (`false`). When enabled, all three supporting clients accept the object form `{ strategy: 'throw' | 'both' }`, and `true` is shorthand for `{ strategy: 'throw' }`. The `throw` strategy parses and throws; `both` additionally `console.error`s the raw `ZodError` before re-throwing, for production observability without giving up fail-fast behaviour.

---

## override.mock

Mock generation overrides:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        mock: {
          properties: {
            '/tag|name/': 'jon',
            email: () => faker.internet.email(),
          },
          schemas: {
            Apple: {
              properties: {
                color: () => faker.helpers.arrayElement(['red', 'green']),
              },
            },
          },
          format: {
            email: () => faker.internet.email(),
            iban: () => faker.finance.iban(),
          },
          required: true,
          nonNullable: true,
          delay: 500,
          arrayMin: 1,
          arrayMax: 10,
          stringMin: 10,
          stringMax: 20,
          numberMin: 0,
          numberMax: 100,
        },
      },
    },
  },
});
```

### properties

Override mock values per property path or regex. Applies to every schema that has a
matching property.

### schemas

Scope property overrides to a named schema, so the same property name can mock differently
per schema (e.g. `color` on `Apple` vs. `Car`). Keyed by schema name; each entry holds a
`properties` map using the same matching rules as `properties` (bare name, `/regex/`, exact
`#.path`). Takes precedence over the global `properties` overrides. See the
[Faker guide](/docs/guides/faker#per-schema-overrides) for a worked example.

### format

Provide custom generators for OpenAPI `format` values.

### required

**Type:** `Boolean`

Make all properties required in mocks.

### nonNullable

**Type:** `Boolean`
**Default:** `false`

When `true`, nullable properties are generated without `faker.helpers.arrayElement([value, null])`. For OpenAPI 3.1 null-union array items (`type: ['string', 'null']`), this also skips null inside `.map()` callbacks. Optional properties may still be omitted via `arrayElement([value, undefined])` unless `required` is also `true`. You can still pass `null` at runtime through the factory's `overrideResponse` argument.

### delay

**Type:** `Number | Function | false`
**Default:** `false`

Response delay in milliseconds. Set to `false` to remove delay.

### fractionDigits

**Type:** `Number`
**Default:** `2`

Number of decimal places for floating-point numbers.

### Array/String/Number Min/Max

Control generated data bounds (`arrayMin`, `arrayMax`, `stringMin`, `stringMax`, `numberMin`, `numberMax`).

### useExamples

**Type:** `Boolean`
**Default:** `false`

Use `example` property from OpenAPI specification for mock generation.

### baseUrl

**Type:** `String`

Base URL for mock handlers.

---

## override.operations

Override by operation ID:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        operations: {
          listPets: {
            mutator: 'src/response-type.js',
            query: {
              useQuery: true,
              useInfinite: false,
            },
            mock: {
              data: () => ({ id: 1, name: 'Buddy' }),
            },
          },
        },
      },
    },
  },
});
```

---

## override.tags

Override by OpenAPI tag (same options as `operations`).

---

## override.operationName

**Type:** `Function`

Custom function to override generated operation names.

The callback receives `(operation, route, verb)`, where `operation` is the OpenAPI
Operation Object, `route` is the operation's route string, and `verb` is Orval's
HTTP verb value. Return a string to set both the method name and the type-name base,
or return `[methodName, typeNameBase]` to control them independently.

**Return `string`** to control both the method name and the type-name base together:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        operationName: (operation, route, verb) => {
          return `custom_${operation.operationId}`;
        },
      },
    },
  },
});
```

**Return `[methodName, typeNameBase]`** to decouple method names from type-identifier names. This is useful for gateway-aggregated specs where multiple services share the same REST patterns (`GET /products`, `GET /orders`) — bare method names are safe per-tag (each service class scopes them), but type names (`*Params`, `*Body`, `*Error`, `*Result`) need to be globally unique to avoid barrel-level collisions with `tags-split` + `splitByTags` + `indexFiles`:

```ts
import { pascal } from '@orval/core';

export default defineConfig({
  api: {
    output: {
      mode: 'tags-split',
      schemas: { path: './model', splitByTags: true },
      override: {
        operationName: (_operation, route, verb) => {
          const segments = route.split('/').filter(Boolean);
          return [
            `${verb}${pascal(segments.slice(2).join('-'))}`,  // getProducts
            `${verb}${pascal(segments.slice(1).join('-'))}`,  // getCatalogProducts
          ];
        },
      },
    },
  },
});
```

Result:

```ts
// catalog/catalog.service.ts
class CatalogService {
  getProducts = (params: GetCatalogProductsParams) => ...;
}

// inventory/inventory.service.ts
class InventoryService {
  getProducts = (params: GetInventoryProductsParams) => ...;
}
```

The first element controls the function/hook name. The second controls the base for all operation-specific TypeScript type identifiers (`*Params`, `*Body`, `*Error`, `*Result`, `*Accept`, zod/hono/effect schema names).

---

## override.components

Add suffixes to generated model names:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        components: {
          schemas: { suffix: 'DTO' },
          responses: { suffix: 'Response' },
          parameters: { suffix: 'Params' },
          requestBodies: { suffix: 'Bodies' },
        },
      },
    },
  },
});
```

Add prefixes to generated component names (available for `schemas`, `responses`, `parameters`, and `requestBodies`). `prefix` is applied to the component itself; `itemPrefix` is applied to the element type when the component is an array (valid for `components.schemas` only). Prefixes are also applied to `$ref` references, so a `Pet` schema with `prefix: 'I'` is referenced as `IPet` everywhere it appears:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        components: {
          schemas: { prefix: 'I', itemPrefix: 'I' },
          responses: { prefix: 'I' },
          parameters: { prefix: 'I' },
          requestBodies: { prefix: 'I' },
        },
      },
    },
  },
});
```

---

The default suffix is `''` for schemas, `'Response'` for responses,
`'Parameter'` for parameters, and `'Body'` for request bodies. Set a suffix to
`''` explicitly to disable it.

For array schemas, `schemas.itemSuffix` controls the suffix of the generated
item type. It defaults to `'Item'` and applies only to `components.schemas`:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        components: {
          schemas: { itemSuffix: 'Element' },
        },
      },
    },
  },
});
```

An inline array response can consequently produce an item type such as
`ListPets200Element`. The item suffix names the generated element type; it does
not change the component schema's structure.

## Type Generation Options

### useDates

**Type:** `Boolean`
**Default:** `false`

Convert `date`/`datetime` to JavaScript `Date` objects.

### useBigInt

**Type:** `Boolean`
**Default:** `false`

Convert `int64`/`uint64` to `BigInt`.

### useTypeOverInterfaces

**Type:** `Boolean`
**Default:** `false`

Use TypeScript `type` instead of `interface`.

### useNamedParameters

**Type:** `Boolean`
**Default:** `false`

Use named parameters object instead of positional arguments.

### useDeprecatedOperations

**Type:** `Boolean`
**Default:** `true`

Include deprecated operations.

### enumGenerationType

**Type:** `'const' | 'enum' | 'union'`
**Default:** `'const'`

How to generate enums:

```ts
// 'const' (default)
export const Example = { foo: 'foo', bar: 'bar' } as const;
export type Example = (typeof Example)[keyof typeof Example];

// 'enum'
export enum Example { foo = 'foo', bar = 'bar' }

// 'union'
export type Example = 'foo' | 'bar';
```

> **Warning:**
> `'enum'` emits a TypeScript `enum` declaration, which type stripping cannot
> remove. If you compile with TypeScript 5.8+ [`erasableSyntaxOnly`](https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly) — for example under Node's native TypeScript support or any type-stripping build step — generated `'enum'` output fails to compile. Use `'const'` (default) or `'union'` instead in that environment.

### aliasCombinedTypes

**Type:** `Boolean`
**Default:** `false`

Create intermediate type aliases for `anyOf`/`oneOf`/`allOf`.

### suppressReadonlyModifier

**Type:** `Boolean`
**Default:** `false`

Suppress `readonly` modifier on properties.

### preserveReadonlyRequestBodies

**Type:** `'strip' | 'preserve'`
**Default:** `'strip'`

Controls how Orval treats `readonly` properties when a schema is reused as a
request body.

- `strip` (recommended): removes readonly modifiers from generated request-body
  types via `NonReadonly<T>`. This is the safest default for most OpenAPI
  specifications because `readOnly` properties are response-oriented.
- `preserve`: keeps readonly modifiers on generated request-body types. Use this
  only when your request DTOs are intentionally immutable and you want that
  immutability reflected in the generated TypeScript types.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        preserveReadonlyRequestBodies: 'strip',
      },
    },
  },
});
```

<Callout title="Tip" type="info">
Prefer separate request and response schemas when your API semantics differ.
This option is mainly useful when a single schema is reused for both request
and response payloads.

> **Note:**
> This setting applies to request bodies regardless of the generated Angular
> style (`HttpClient` or `httpResource`). `httpResource` still sends request
> payloads, so the same request-body guidance applies.

### useNullForOptional

**Type:** `Boolean`
**Default:** `false`

Type optional properties as `T | null` instead of just `T`. Useful for JSON:API compatibility where `null` explicitly indicates "no value".

```ts
// Default (false)
export interface Pet {
  id: number;
  name?: string;
  tag?: string;
}

// With useNullForOptional: true
export interface Pet {
  id: number;
  name?: string | null;
  tag?: string | null;
}
```

### includeZodSchemaInArguments

**Type:** `Boolean`
**Default:** `false`

Pass the zod schema of the response to the custom `mutator` as an extra
`schema` option, so the mutator can validate the response itself.

A custom mutator issues the request on its own, so the `Schema.parse()` call
Orval generates for `runtimeValidation` never runs (see
[#2858](https://github.com/orval-labs/orval/issues/2858)). Enabling this option
hands the schema to the mutator instead.

Supported by the `fetch` client and by the query clients using
`httpClient: 'fetch'`. Requires `schemas: { type: 'zod' }` and
`override.fetch.runtimeValidation: true`. The schema is omitted for operations
without a validatable response — primitive or `void` responses, and
`application/x-ndjson` streams.

```ts
export default defineConfig({
  petstore: {
    output: {
      client: 'fetch',
      schemas: { path: 'src/gen/model', type: 'zod' },
      override: {
        includeZodSchemaInArguments: true,
        mutator: { path: './src/custom-fetch.ts', name: 'customFetch' },
        fetch: { runtimeValidation: true },
      },
    },
  },
});
```

```ts
import type { ZodType } from 'zod';

export const customFetch = async <T>(
  url: string,
  options: RequestInit & { schema?: ZodType<T> },
): Promise<T> => {
  const { schema, ...init } = options;
  const response = await fetch(url, init);
  const data = await response.json();

  return schema ? schema.parse(data) : (data as T);
};
```

> **Note:**
> `schema.parse()` throws a `ZodError` on a mismatch. Use `safeParse()` in the
> mutator if you would rather handle validation failures yourself.

## factoryMethods

**Type:** `Object`
**Default:** `{ generate: false }`

Generate factory methods for DTOs (Data Transfer Objects) initialized with safe default values. Useful for testing and initializing empty state.
Functionality handles OpenAPI `readOnly` and `writeOnly` flags to generate appropriate payload structures:
- **Required properties:** Always included in the factory output, regardless of their visibility flags.
- **Optional `readOnly` properties:** Always omitted from the factory output, as they would be dropped by the server.
- **Optional `writeOnly` properties:** Always included in the factory output (even if `includeOptionalProperty` is set to `false`).

```ts
export default defineConfig({
  petstore: {
    output: {
      factoryMethods: {
        functionNamePrefix: 'create',
        mode: 'split',
        includeOptionalProperty: true,
        outputDirectory: `#output.workspace.schemas`,
      },
    },
  },
});
```

### functionNamePrefix

**Type:** `String`
**Default:** `'create'`

Prefix for the generated factory function names.

### mode

**Type:** `'single' | 'split' | 'single-split'`
**Default:** `'split'`

Where to generate the factory methods:
- `single`: Appends the factory function to the schema file.
- `split`: Creates a `{schema}.factory.ts` with factory method. By default it is placed next to schema file.
- `single-split`: Aggregates all factory methods into a single `factoryMethods.ts` file.

### includeOptionalProperty

**Type:** `boolean`
**Default:** `true`

Determines whether optional schema properties are included in the default factory output.

### outputDirectory

**Type:** `String`
**Default:** `#output.workspace.schemas`

Defaults to the value configured in `#output.workspace.schemas`.
Determines where factory methods will be generated (can be used to generated methods away from schema directory).
Takes effect only when used `mode` is `split` or `single-split`.
---

## Other Options

### allParamsOptional

**Type:** `Boolean`
**Default:** `false`

Let callers leave parameters unresolved.

Path parameters keep their position in the signature but widen to accept a missing value, and the query/header parameters object becomes optional:

```ts
// allParamsOptional: false
export const getPet = async (petId: string, params: GetPetParams, ...)

// allParamsOptional: true
export const getPet = async (petId: string | undefined | null, params?: GetPetParams, ...)
```

Properties inside the parameters object keep whatever the document says — a `required: true` query parameter stays required within `GetPetParams`.

This is useful with the TanStack Query clients, where a hook is often called before its id is known and the generated `enabled` guard (or [`useSkipToken`](#useskiptoken)) already holds the request back until then.

### urlEncodeParameters

**Type:** `Boolean`
**Default:** `false`

Wrap each path parameter with `encodeURIComponent(String(...))` in generated URL helpers. This option only affects path parameters; query parameters are typically encoded by the underlying client (`URLSearchParams`, `axios`, etc.).

Path parameters are stringified via `String(value)` before encoding, so array (`style: simple|matrix|label`) and object path parameters are not serialized according to their OpenAPI `style` — they fall back to the default `String(value)` representation.

### optionsParamRequired

**Type:** `Boolean`
**Default:** `false`

Make the `options` parameter required. Since the `options` parameter appears last in the parameter-set, any preceding parameters will also be required.

### propertySortOrder

**Type:** `'Alphabetical' | 'Specification'`
**Default:** `'Specification'`

How to sort properties in generated types.

### `$dynamicRef` / `$dynamicAnchor` support

Orval automatically resolves JSON Schema 2020-12 `$dynamicRef` / `$dynamicAnchor` keywords in OpenAPI 3.1 specs. No configuration is needed.

#### Supported patterns

| Pattern | Description |
|---------|-------------|
| Generic template emission | Schemas with `$defs` entries that have `$dynamicAnchor` but no `$ref` are emitted as TypeScript generic interfaces (e.g., `interface PaginatedResponse<itemType>`). |
| Type alias binding | Schemas that `$ref` a generic template and bind `$defs` entries with `$dynamicAnchor` + `$ref` are emitted as type aliases (e.g., `type UserListResponse = PaginatedResponse<User>`). |
| Self-referential `$dynamicAnchor` | Recursive schemas where `$dynamicRef` resolves to the declaring schema itself (e.g., tree nodes). |
| `allOf` bound aliases | Schemas that combine a generic template reference with additional properties via `allOf` emit intersection types (e.g., `type X = Template<Args> & { extra }`). |

#### Generic template example

Define a reusable generic schema with an unbound `$dynamicAnchor` in `$defs`:

```yaml
components:
  schemas:
    PaginatedResponse:
      $defs:
        itemType:
          $dynamicAnchor: itemType
          not: {}
      type: object
      properties:
        items:
          type: array
          items:
            $dynamicRef: '#itemType'
        total:
          type: integer
```

Then bind it to concrete types:

```yaml
    UserListResponse:
      $defs:
        itemType:
          $dynamicAnchor: itemType
          $ref: '#/components/schemas/User'
      $ref: '#/components/schemas/PaginatedResponse'

    OrderListResponse:
      $defs:
        itemType:
          $dynamicAnchor: itemType
          $ref: '#/components/schemas/Order'
      $ref: '#/components/schemas/PaginatedResponse'
```

Generated TypeScript:

```ts
export interface PaginatedResponse<itemType> {
  items: itemType[];
  total: number;
}

export type UserListResponse = PaginatedResponse<User>;
export type OrderListResponse = PaginatedResponse<Order>;
```

The generic parameter name (`itemType`) comes from the `$dynamicAnchor` value. The type alias name (`UserListResponse`) comes from the schema key in `components.schemas`. Endpoints that reference a bound alias use the alias name directly (e.g., `Promise<AxiosResponse<UserListResponse>>`).

#### Self-referential `$dynamicAnchor` example

When a schema declares `$dynamicAnchor` and uses `$dynamicRef` with the same anchor, the type resolves to itself:

```yaml
components:
  schemas:
    BaseCategory:
      $dynamicAnchor: category
      type: object
      properties:
        id:
          type: string
        children:
          type: array
          items:
            $dynamicRef: '#category'

    LocalizedCategory:
      $dynamicAnchor: category
      allOf:
        - $ref: '#/components/schemas/BaseCategory'
        - type: object
          properties:
            displayName:
              type: string
```

Generated TypeScript:

```ts
export interface BaseCategory {
  id?: string;
  children?: BaseCategory[];
}

export interface LocalizedCategory {
  id?: string;
  children?: LocalizedCategory[];
  displayName?: string;
}
```

Each schema's `$dynamicRef: '#category'` resolves to its own type because it declares `$dynamicAnchor: category`.

#### Output layout with `$dynamicRef` generics

Generic templates, bound aliases, and their type arguments are all emitted as individual model files in the same shared location — they are never duplicated per tag. In `tags` and `tags-split` mode, every tag's service file imports from a single shared schema source.

With [`schemas`](#schemas) configured and `tags-split` mode ([`indexFiles`](#indexfiles) shown at its default, `true`):

```
models/
├── index.ts                      ← barrel re-exports everything (indexFiles: true)
├── apiEnvelopeTemplate.ts        ← generic template (ApiEnvelopeTemplate<T>)
├── paginatedTemplate.ts          ← generic template (PaginatedTemplate<T>)
├── pet.ts                        ← domain type
├── owner.ts                      ← domain type
├── paginatedPetItems.ts          ← bound alias (PaginatedTemplate<Pet>)
└── paginatedOwnerItems.ts        ← bound alias (PaginatedTemplate<Owner>)
pets/
└── pets.ts                       ← import { ... } from '../models'
owners/
└── owners.ts                     ← import { ... } from '../models'
```

With [`indexFiles: false`](#indexfiles), no barrel is generated and service files import each schema individually (e.g., `import type { Pet } from '../models/pet'`).

Without a dedicated `schemas` directory, all schemas go into a single `petstore.schemas.ts` file at the output root.

When using [`input.filters.tags`](/docs/reference/configuration/input#tags) to filter endpoints, schemas referenced exclusively through `$dynamicAnchor` + `$ref` bindings in inline response `$defs` are automatically discovered and included in the output — no manual [`filters.schemas`](/docs/reference/configuration/input#schemas) configuration is needed.

#### Limitations

- Each schema in `components.schemas` is generated once with a single dynamic scope. If the same named component is referenced by multiple endpoints that each provide different `$defs` bindings, only one binding applies. The common pattern — putting `$defs` bindings on inline response schemas — works correctly.
- `$dynamicRef` values targeting external documents (e.g., `other.json#anchor`) fall back to `unknown`.
- Inline `$defs` entries without `$ref` that have `$dynamicAnchor` are treated as generic type parameters, not concrete bindings.

### contentType

Filter content types:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        contentType: {
          include: ['application/json'],
          exclude: ['application/xml'],
        },
      },
    },
  },
});
```

### splitByContentType

**Type:** `Boolean` **Default:** `false`

When an endpoint's `requestBody` supports multiple content types (e.g. `application/json` and `multipart/form-data`), generate a separate function for each content type instead of combining them into a single function with a union type parameter.

Each generated function is suffixed with the content type name (e.g. `WithJson`, `WithFormData`).

```ts
// Default (false) — single function with union body
updateProfile(body: FormDataType | JsonType) => { ... }

// With splitByContentType: true — separate function per content type
updateProfileWithFormData(body: FormDataType) => { ... }
updateProfileWithJson(body: JsonType) => { ... }
```

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        splitByContentType: true,
      },
    },
  },
});
```

> If the endpoint only has a single content type, no suffix is added and the behavior is the same as the default.

### formData

**Type:** `Boolean | String | Object`

Customize form data generation. If an object is provided, specify `path`, `name`, and optionally `default: true` for default export.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        formData: {
          path: './api/mutator/custom-form-data-fn.ts',
          name: 'customFormDataFn',
          // default: true
        },
      },
    },
  },
});
```

```ts
export const customFormDataFn = <Body>(body: Body): FormData => {
  const formData = new FormData();
  // Custom implementation
  Object.entries(body as Record<string, any>).forEach(([key, value]) => {
    if (value !== undefined) {
      formData.append(key, value);
    }
  });
  return formData;
};
```

#### arrayHandling

**Type:** `'serialize' | 'serialize-with-brackets' | 'explode'`
**Default:** `'serialize'`

Specifies how FormData handles arrays:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        formData: {
          arrayHandling: 'serialize-with-brackets',
        },
      },
    },
  },
});
```

- `serialize`: `formData.append('items', JSON.stringify(value))`
- `serialize-with-brackets`: `formData.append('items[]', JSON.stringify(value))`
- `explode`: Expands nested objects with indexed keys

### formUrlEncoded

**Type:** `Boolean | String | Object`

Customize form URL encoded data generation:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        formUrlEncoded: {
          path: './api/mutator/custom-form-url-encoded-fn.ts',
          name: 'customFormUrlEncodedFn',
        },
      },
    },
  },
});
```

```ts
export const customFormUrlEncodedFn = <Body>(body: Body): URLSearchParams => {
  const params = new URLSearchParams();
  Object.entries(body as Record<string, any>).forEach(([key, value]) => {
    if (value !== undefined) {
      params.append(key, String(value));
    }
  });
  return params;
};
```

### paramsSerializer

**Type:** `String | Object`

> **Note:** Valid for Axios, Angular, and the fetch client.

Custom parameter serializer for query parameters. When set, the generated URL helper delegates query string building entirely to this function instead of using the built-in logic.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        paramsSerializer: {
          path: './api/mutator/custom-params-serializer-fn.ts',
          name: 'customParamsSerializerFn',
        },
      },
    },
  },
});
```

For Axios and Angular the function receives the params object and can return any value Axios/Angular accepts. For the fetch client it must return a `string` (the raw query string without the leading `?`):

```ts
// Axios / Angular
export const customParamsSerializerFn = (
  params: Record<string, any>,
): string => {
  return Object.entries(params)
    .filter(([_, v]) => v !== undefined)
    .map(([k, v]) => `${k}=${encodeURIComponent(v)}`)
    .join('&');
};

// fetch client — must return a string
export const customParamsSerializer = (
  params: Record<string, unknown> | undefined,
): string =>
  new URLSearchParams(
    Object.entries(params ?? {})
      .filter(([_, v]) => v !== undefined)
      .flatMap(([k, v]) =>
        Array.isArray(v)
          ? v.map((item) => [k, String(item)])
          : [[k, String(v)]],
      ),
  ).toString();
```

### paramsSerializerOptions

**Type:** `Object`

> **Note:** Only valid when using Axios or Angular. Only used when `paramsSerializer` is not defined.

Use `qs` library for parameter serialization:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        paramsSerializerOptions: {
          qs: {
            arrayFormat: 'repeat',
          },
        },
      },
    },
  },
});
```

### paramsFilter

**Type:** `String | Object`

> **Note:** Only valid for the `angular` client, or `angular-query` when `httpClient: 'angular'`.

Replaces the built-in query-parameter filter that the Angular client applies
before handing params to `HttpParams`. When set, orval does **not** strip
`null`/`undefined` or non-primitive values for you — your function returns
exactly the object `HttpParams` (or a configured `paramsSerializer`) receives.

This option intentionally lives at `override.paramsFilter` rather than
`override.angular.paramsFilter` so the same request-shaping override can be used
globally or narrowed per operation/tag, just like `mutator` and
`paramsSerializer`.

When a `paramsSerializer` is configured, orval already preserves
schema-declared object and array-of-object params so the serializer can
handle them; without a serializer those params are dropped. See the
[Angular guide](/docs/guides/angular#query-parameter-filtering). Use
`paramsFilter` when you need the raw object without a serializer, or for
any control that the schema cannot express.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        paramsFilter: {
          path: './api/mutator/custom-params-filter-fn.ts',
          name: 'customParamsFilterFn',
        },
      },
    },
  },
});
```

```ts
export const customParamsFilterFn = (
  params: Record<string, unknown>,
): Record<string, unknown> => {
  const result: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(params)) {
    if (value !== undefined) {
      result[key] = value;
    }
  }
  return result;
};
```

### useDates

**Type:** `Boolean`
**Default:** `false`

Convert OpenAPI `date` or `datetime` to JavaScript `Date` objects instead of `string`.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        useDates: true,
      },
    },
  },
});
```

> **Important:** You must provide an Axios converter to convert serialized date strings to `Date` objects. This option only affects the TypeScript definition.

If you also want runtime conversion, prefer `useDatesTransform` below; the interceptor approach traverses every response and can convert date-looking strings that are not schema dates.

```ts
import axios from 'axios';

const client = axios.create({ baseURL: '' });

client.interceptors.response.use((originalResponse) => {
  handleDates(originalResponse.data);
  return originalResponse;
});

export default client;

const isoDateFormat =
  /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d*)?(?:[-+]\d{2}:?\d{2}|Z)?$/;

function isIsoDateString(value: any): boolean {
  return value && typeof value === 'string' && isoDateFormat.test(value);
}

export function handleDates(body: any) {
  if (body === null || body === undefined || typeof body !== 'object')
    return body;

  for (const key of Object.keys(body)) {
    const value = body[key];
    if (isIsoDateString(value)) {
      body[key] = new Date(value); // default JS conversion
      // body[key] = parseISO(value); // date-fns conversion
      // body[key] = luxon.DateTime.fromISO(value); // Luxon conversion
    } else if (typeof value === 'object') {
      handleDates(value);
    }
  }
}
```

> If using `fetch` client with `useDates: true`, query parameters of type Date are stringified using `toISOString()`.

### useDatesTransform

**Type:** `Boolean`
**Default:** `false`

Use this property to also convert dates at runtime. While `useDates` only
changes the generated TypeScript types, `useDatesTransform` additionally
generates a small `deserialize<OperationName>Response` function for every
operation whose response schema declares `format: date` or
`format: date-time` fields, and chains it onto the generated call:

```ts
export const getOrderDetails = (orderId: string) => {
  return customInstance<OrderDetails>({ url: `/orders/${orderId}`, method: 'GET' }).then(
    deserializeGetOrderDetailsResponse,
  );
};
```

Only schema-declared date fields are converted — no response-wide traversal,
no pattern matching on strings — and operations without date fields generate
no extra code. Setting `useDatesTransform: true` implies `useDates: true`.
This removes the need for the axios interceptor shown under `useDates`.

Current limitations: a `oneOf`/`anyOf` without an OpenAPI
[`discriminator`](https://spec.openapis.org/oas/v3.1.0#discriminator-object)
`mapping` is skipped, since there's no static way to tell which variant a
given payload matched; a discriminated union with an explicit `mapping` is
converted, emitting a `switch` on the discriminator property with one `case`
per mapping key. `additionalProperties` maps are not converted, responses
with multiple success shapes are skipped, and recursive schemas are left
untouched entirely — converting only the levels above the cycle would leave
deeper dates as strings while the generated types claim `Date`. Only the
axios-based clients are wired (`react-query`, `vue-query`, `svelte-query`,
and `solid-query` with `httpClient: 'axios'`).

### useBigInt

**Type:** `Boolean`
**Default:** `false`

Convert OpenAPI `int64` and `uint64` format to JavaScript `BigInt` objects instead of `number`.

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        useBigInt: true,
      },
    },
  },
});
```

### requestOptions

**Type:** `Object | Boolean`

Configure or remove request options. Set to `false` to remove entirely.

### jsDoc.filter

**Type:** `Function`

Customize JSDoc generation by filtering and transforming schema entries:

```ts
export default defineConfig({
  petstore: {
    output: {
      override: {
        jsDoc: {
          filter: (schema) => {
            const allowlist = [
              'type', 'format', 'maxLength', 'minLength',
              'description', 'minimum', 'maximum', 'pattern',
              'nullable', 'enum',
            ];
            return Object.entries(schema || {})
              .filter(([key]) => allowlist.includes(key))
              .map(([key, value]) => ({ key, value }))
              .sort((a, b) => a.key.length - b.key.length);
          },
        },
      },
    },
  },
});
```

Result:

```ts
export interface Pet {
  /**
   * @type integer
   * @format int64
   */
  id: number;
  /**
   * @type string
   * @description Name of pet
   */
  name: string;
}
```
