OrvalOrval

Programmatic API

Use Orval programmatically in your build scripts

Integrate Orval code generation into your build processes, scripts, or tools.

Basic Usage

import orval from 'orval';

// Generate using a config file path
await orval('./orval.config.js');

// Generate using current directory's orval config
await orval();

Or use the named export:

import { generate } from 'orval';

await generate('./orval.config.js');

Direct Configuration

Pass a configuration object directly:

import { generate, type Options } from 'orval';

const config: Options = {
  input: {
    target: './api-spec.yaml',
  },
  output: {
    target: './src/api.ts',
    client: 'axios',
  },
};

await generate(config);

Global Options Override

Override config settings with global options. See the GlobalOptions interface for all available options.

import { generate, type GlobalOptions } from 'orval';

const globalOptions: GlobalOptions = {
  // File watching
  watch: true, // Enable watch mode (boolean)
  // watch: './specs/**/*.yaml',        // Watch specific file pattern (string)
  // watch: ['./specs/*.yaml'],         // Watch multiple patterns (string[])

  // Output control
  clean: true, // Clean all output directories (boolean)
  // clean: ['./src/api', './types'],   // Clean specific directories (string[])
  output: './src/generated', // Override output directory

  // Code formatting (only one formatter can be used at a time)
  formatter: 'prettier', // 'prettier' | 'biome' | 'oxfmt'

  // HTTP client configuration
  client: 'fetch', // Override HTTP client
  httpClient: 'fetch', // HTTP implementation: 'axios' | 'fetch'

  // Generation mode
  mode: 'split', // Output mode: 'single' | 'split' | 'tags' | 'tags-split'

  // Mock data generation
  mock: true, // Enable mock data generation
  // mock: { generators: [{ type: 'msw', delay: 1000 }] },  // Configure mock options

  // TypeScript configuration
  tsconfig: './tsconfig.json', // Custom tsconfig path
  // tsconfig: { compilerOptions: {...} },  // Inline tsconfig

  // Package configuration
  packageJson: './package.json',
  input: './api-spec.yaml',

  // Logging
  logLevel: 'error', // Only log errors

  // Error handling
  throwOnError: true, // Throw initial generation errors instead of only logging them
};

await generate('./orval.config.js', process.cwd(), globalOptions);

Custom Workspace

Specify a custom workspace directory:

import { generate } from 'orval';

const workspace = '/path/to/your/project';
await generate('./orval.config.js', workspace);

Function Signature

function generate(
  optionsExport?: string | OptionsExport,
  workspace?: string,
  options?: GlobalOptions,
): Promise<void>;

Parameters:

  • optionsExport: Path to config file or configuration object
  • workspace: Working directory (defaults to process.cwd())
  • options: Global options to override config settings

Error Handling

By default, generate() logs initial generation errors and resolves after processing the configured project or projects. Set throwOnError when a script needs to catch initial generation failures and decide how to handle them:

import { generate } from 'orval';

try {
  await generate('./orval.config.js', process.cwd(), {
    throwOnError: true,
  });
} catch {
  process.exit(1);
}

generate() logs the error through the active reporter before rethrowing. logger.error is a no-op outside withReporter, so do not use it in this catch block.

When a config file contains multiple projects, throwOnError stops on the first generation error during the initial run instead of continuing with later projects. Watch mode generation errors are still logged after the watcher has started.

Reporter

Reporter selection is a programmatic execution concern, not an orval.config.ts option. Built-in packages emit structured events (message, packageName, and optional projectName) to the reporter that is active for the current async call chain.

Entry pointDefault
Lower-level APIs (generateSpec, helpers, formatters)No-op
CLI (orval)Console
Public generate()Console, unless an outer withReporter is already active

Use withReporter to install a reporter for one call chain. An outer reporter always wins over generate()'s console default, so tests can silence output without changing production callers.

import { generate, withReporter, noopReporter, consoleReporter } from 'orval';

// Quiet a programmatic generate() in tests
await withReporter(noopReporter, () => generate(config));

// Opt lower-level APIs into the existing terminal output
await withReporter(consoleReporter, () => generateSpec(workspace, options));

Custom reporters receive the structured event. When a project is in scope, the logger prefixes message with that project name. Messages keep their current wording and ANSI styling; strip colors if you need plain text.

import { generate, withReporter, type OrvalReporter } from 'orval';

const reporter: OrvalReporter = {
  info: (event) => process.stdout.write(`${event.packageName}: ${event.message}\n`),
  warn: (event) => process.stderr.write(`${event.packageName}: ${event.message}\n`),
  error: (event) => process.stderr.write(`${event.packageName}: ${event.message}\n`),
  verbose: (event) => process.stderr.write(`${event.packageName}: ${event.message}\n`),
  debug: (event) => {
    if (process.env.DEBUG) {
      process.stderr.write(`${event.packageName}: ${event.message}\n`);
    }
  },
};

await withReporter(reporter, () => generate(config));

To assert one or more events in a test, override only the levels you care about:

import { generate, noopReporter, withReporter } from 'orval';
import { vi } from 'vitest';

const warn = vi.fn();

await withReporter({ ...noopReporter, warn }, () => generate(config));

expect(warn).toHaveBeenCalledWith(
  expect.objectContaining({
    packageName: 'orval',
    message: expect.stringContaining('symbolic link'),
  }),
);

Watch Mode

import { generate } from 'orval';

// Enable watch mode
await generate('./orval.config.js', process.cwd(), {
  watch: true,
});

// Watch specific files/directories
await generate('./orval.config.js', process.cwd(), {
  watch: ['./specs/*.yaml', './src/custom-types.ts'],
});

Build Scripts Integration

package.json
{
  "scripts": {
    "generate": "node scripts/generate-api.js",
    "dev": "npm run generate && next dev",
    "build": "npm run generate && next build"
  }
}
scripts/generate-api.js
const { generate } = require('orval');

async function main() {
  try {
    await generate();
    console.log('API client generated successfully');
  } catch (error) {
    console.error('Failed to generate API client:', error);
    process.exit(1);
  }
}

main();

On this page