# orval: generating TypeScript clients from an OpenAPI spec

> orval turns an OpenAPI v3 or Swagger v2 document into type-safe TypeScript clients, including React Query and SWR hooks, MSW mocks and zod schemas. It is a code generator, so the review question is what it emits and what it leaves you to maintain.

**orval-labs/orval** — orval is able to generate client with appropriate type-signatures (TypeScript) from any valid OpenAPI v3 or Swagger v2 specification, either in yaml or json formats. 🍺

- Repository: https://github.com/orval-labs/orval
- Website: https://orval.dev
- Stars: 6,503 · Forks: 688
- Language: TypeScript
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/orval-labs-orval

## The problem orval solves, and for whom

An OpenAPI document describes endpoints, request bodies and response shapes. It does not give a frontend anything to call. Teams usually close that gap by hand: write a fetch wrapper, copy the response types out of the spec, keep both in sync as the API changes. That copying is where drift starts, and drift shows up as a runtime error in a component that TypeScript was supposed to protect.

orval closes the gap by generating the client. The README states that it produces type-safe JS clients (TypeScript) from any valid OpenAPI v3 or Swagger v2 specification, in yaml or json. The audience is therefore teams that already own a specification and want the calling code derived from it rather than written beside it. The supported target list is the clearest signal of who that is: React, React Query, React with swr, Vue Query, Pinia Colada, Svelte Query, Solid Query, SolidStart, Angular, Angular Query, Hono, zod, Effect, native fetch and mcp. If your stack is not on that list, the generated output will not fit without work.

The project is MIT licensed, and the README notes that version 8.0.0+ carries a set of changes with a migration guide linked from the top of the file. That note matters more than the feature list for anyone upgrading an existing installation.

## What orval actually emits: models, requests, hooks, mocks

The README describes the output as models, requests, hooks, mocks and more, for the supported clients. Read that as three layers produced from one input. The models are the TypeScript types derived from the schemas in the specification. The requests are the functions that call the endpoints. The hooks and mocks are the framework-specific wrappers, for example React Query hooks or MSW handlers, generated only when the configuration asks for that client.

The configuration drives all of it. Orval's Docker usage passes a config file explicitly with --config ./orval.config.ts, which tells you the config is a TypeScript module the tool loads at generation time. The repository layout supports the same reading: samples/ contains one directory per target (react-app, react-query, svelte-query, vue-query, pinia-colada, solid-query, solid-start, react-app-with-swr, angular-app, angular-query, hono, swr-with-effect, next-app-with-fetch, mcp, and others), and each sample is a working project whose generated output is checked in. The root package.json has an update-samples script that rebuilds the packages and regenerates every sample, plus test:snapshots scripts that regenerate and then compare against tests/__snapshots__. That structure is the honest description of how orval is developed: the generated code is version-controlled and diffed, so a change in the generator shows up as a change in the samples.

One detail worth noting for anyone whose spec is split across files: samples/dynamic-ref/ exists in the repository, which indicates that references resolved at generation time are a supported scenario rather than an edge case bolted on later.

## Installing orval and generating a first client

The README does not walk through a plain npm install in the text shown, but the Dockerfile makes the package name and version argument explicit: it installs orval globally with npm install -g "orval@${ORVAL_VERSION}", defaulting ORVAL_VERSION to latest. The same package is what the npm version badge at the top of the README points at, and the Docker entrypoint is orval itself.

The Docker route is the one the README documents in full, and it exists because of a version constraint: orval 8+ requires Node.js 22.18 or newer, and the README says projects on an older Node LTS can run code generation with the official image. The basic invocation mounts the current directory into /app and runs the image there:

```bash
docker run --rm -v "$(pwd):/app" -w /app ghcr.io/orval-labs/orval
```

The README gives the equivalent lines for Windows Git Bash, CMD and PowerShell, including MSYS_NO_PATHCONV=1 for Git Bash. If your spec is served by a local API, the README documents pointing orval at the host through host.docker.internal and passing the config file by name:

```bash
docker run --rm -v "$(pwd):/app" -w /app -e ORVAL_SWAGGER_URL="https://host.docker.internal:7142/swagger/v1/swagger.json" -e NODE_TLS_REJECT_UNAUTHORIZED=0 ghcr.io/orval-labs/orval --config ./orval.config.ts
```

On native Linux Docker the README adds --add-host=host.docker.internal:host-gateway to that command. Before the official image is published, the README says to replace ghcr.io/orval-labs/orval with orval:local when testing locally.

The first real use is then: point the config at your specification, run the command, and read the files it writes into your project. The repository's samples are the reference for what correct output looks like for each target, and samples/README.md is the entry point to them. Because the samples are ordinary workspaces, you can compare your generated directory against the matching sample to see whether a missing hook or type is a configuration problem or a generator limitation.

## Where orval is the wrong tool

orval generates files. If your team wants a client that adapts at runtime to whatever the server returns, or wants to avoid a build step in the pipeline, a generated client is a mismatch: you now own the generated code's location, its formatting, its exclusion from linting, and the moment in CI when it is regenerated. The repository itself shows this cost. The root package.json keeps separate scripts for linting samples and linting snapshots (lint:samples, lint:snapshots) alongside the main lint script, and a dedicated test:snapshots pipeline that rebuilds the packages before regenerating. A project adopting orval inherits a smaller version of that problem: deciding what to do with files nobody edits by hand.

The second boundary is the input. Everything orval does depends on the specification being valid and current. If the spec lags behind the deployed service, orval will faithfully generate a client for an API that no longer exists, and the type safety will be worse than useless because it will look correct. The README's claim is explicitly limited to "any valid OpenAPI v3 or Swagger v2 specification", and validity is not something the tool can create.

Third, the target list is a constraint, not a menu of equivalents. Generating zod schemas and generating React Query hooks are different jobs with different outputs; picking the wrong generator means regenerating later. And the Node version floor of 22.18 for orval 8+ is a real adoption blocker for teams pinned to an older LTS, which is exactly why the Docker image exists.

## orval compared with a runtime client approach

The closest alternative in the search data is hey api, and the difference is worth stating precisely rather than as a preference. A runtime-first client reads the specification at build or runtime and exposes a generic calling surface; the types are derived from the document through a type-level transformation, and the code you write is a call with a path and options. orval takes the other route: it writes concrete files into your repository, one function or hook per operation, with names taken from the specification. The consequence is that you can open the generated file and read exactly what will be sent, and you can grep for a hook name. The cost is that the file count grows with the API surface, and the generated directory becomes part of your repository's diff noise.

Within orval's own approach there is a second axis: which target you generate for. The samples directory makes this concrete. react-query, vue-query, svelte-query, solid-query, angular-query and pinia-colada are separate samples because the emitted hook code differs per framework even when the underlying specification is identical. swr-with-zod and swr-with-effect exist as separate samples for the same reason: the validation or effect layer changes the output. Choosing a target is choosing a runtime dependency, not just a code style.

## Maintenance, releases and the licence position

The last push to the repository was on 2026-09-22, and the most recent releases listed are v8.36.0 on 2026-09-21, v8.35.0 on 2026-09-20 and v8.34.0 on 2026-09-18. The repository is not archived. That pattern, three releases in four days, is the practical maintenance signal here: the project ships often, and the version number moves quickly. For an adopter, frequent releases mean the upgrade cost is not a single event but an ongoing line item, and the README's pointer to a migration guide for 8.0.0+ is the place to start when a major version lands.

The repository is MIT licensed, and the root package.json carries "license": "MIT". MIT is permissive: it allows use, modification and redistribution with the licence and copyright notice retained. That is the whole of what the project states; questions about generated output ownership or about combining orval with differently licensed dependencies are for your own legal review, not something the repository answers.

Contributions have their own stated policy. The README's note about AI asks contributors not to submit AI-generated output without reviewing it, requires that every change have a clear intent, and says the effort of understanding the codebase is the contributor's responsibility rather than the reviewer's. It also states that new contributors remain welcome and will be supported through review. If you plan to patch the generator rather than only consume it, that paragraph is the contract you are agreeing to.

## Conclusion

Adopt orval when your team already treats the OpenAPI document as the contract and wants the client, the hooks and the mocks regenerated from it, and when the chosen target (React Query, SWR, Angular, zod, fetch) matches the stack you actually ship. Skip it when your API surface is small enough to hand-write, when you cannot keep the specification current, or when you need a runtime client rather than generated files. Before committing, verify three things: that your spec produces the output you expect for one endpoint, that your Node version satisfies the 8+ requirement of Node.js 22.18 or newer, and that the generated files are excluded from your linter in the way the samples do it, since the repository keeps separate lint scripts for samples and snapshots.

## FAQ

### What is orval?

orval is a code generator that produces type-safe TypeScript clients from an OpenAPI v3 or Swagger v2 specification in yaml or json. It can emit models, requests, hooks and mocks for targets such as React Query, SWR, Angular, zod and native fetch. It is MIT licensed and its documentation lives at orval.dev.

### How do you use orval?

You supply a specification and a config file, then run the generator; the README's Docker examples invoke the image with --config ./orval.config.ts. The generated files are written into your project, and the samples directory in the repository shows the expected output for each supported target.

### How does orval compare with hey api?

orval writes concrete generated files into your repository, one function or hook per operation, whereas a runtime-oriented client derives its types from the document without emitting that per-operation code. The repository's samples are the reference for what orval's output looks like.

### Is orval AI?

No. orval is a TypeScript code generator for OpenAPI specifications. The README does contain a note about AI, but it is a contribution policy asking people not to submit unreviewed AI-generated output in pull requests.

## Sources

- [License: MIT](https://github.com/orval-labs/orval/blob/master/LICENSE)
- [orval-labs/orval on GitHub](https://github.com/orval-labs/orval)
- [Project website](https://orval.dev)
- [README](https://github.com/orval-labs/orval/blob/master/README.md)
- [Releases](https://github.com/orval-labs/orval/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/orval-labs-orval
