# oapi-codegen: generating Go servers, clients and models from an OpenAPI 3 spec

> oapi-codegen turns OpenAPI 3.0 and 3.1 documents into Go types, clients and server interfaces. It is a good fit for Go teams that want plain generated code they can read, and a poor fit for anyone who wants a runtime framework doing the work for them.

**oapi-codegen/oapi-codegen** — Generate Go client and server boilerplate from OpenAPI 3 specifications

- Repository: https://github.com/oapi-codegen/oapi-codegen
- Stars: 8,603 · Forks: 1,060
- Language: Go
- License: Apache-2.0
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/oapi-codegen-oapi-codegen

## The boilerplate problem oapi-codegen removes

Every Go service that speaks HTTP starts the same way: a struct per request and response body, JSON tags, a mux with paths registered, a client with methods that build URLs and decode replies. None of that is the product. oapi-codegen exists so that work is derived from the OpenAPI document instead of typed by hand.

The audience is narrow and specific. You are writing Go. You already have an OpenAPI 3.0 or 3.1 specification, or you are willing to write one. You want the generated output to look like something a Go developer would have written, and you are willing to accept verbose code in exchange for not having a framework between you and net/http. The README states the design decisions plainly: idiomatic Go where possible, fairly simple generated code, and support for as much of OpenAPI 3.0 and 3.1 as the Go type system allows.

The tool is a command-line program and a library. That second part matters more than it first appears. Anything the CLI can do can be driven from Go code, which is how teams with unusual naming rules or house templates get their output.

## What the generator actually produces

oapi-codegen reads a specification and emits Go source. The README splits the output into three modes: HTTP models, API clients, and server-side boilerplate. You choose what you want through configuration, so a project that only needs shared types can generate those and nothing else.

On the server side the generated code gives you an interface to implement plus the routing that connects HTTP requests to it. The strict server option is the more interesting variant: instead of handlers that receive a raw http.ResponseWriter and *http.Request, you implement methods that take and return typed values, and the generated layer handles decoding and encoding. That removes a class of mistakes around status codes and body writing, at the cost of a layer you do not control.

Client generation follows the same idea in reverse. The README notes that server URLs can be baked into the generated client, and it also documents a known wrinkle: duplicate types can be generated for a client's response object types. That is the kind of detail worth knowing before you diff a large generated file and wonder why two nearly identical structs exist.

Everything is driven by the specification. If a field is optional in the document, it tends to become a pointer in Go unless you configure otherwise; the README has a section on globally skipping the optional pointer, which tells you the default is pointers and that some teams find them noisy enough to turn off.

## Installing oapi-codegen and generating your first file

The project moved from the Deepmap organisation to its own, and the README is explicit that import paths changed with the v2.3.0 tag. If you are on v2.2.0 or below, the old path still applies. For anything current, install from the new module path. The tool requires Go 1.25 or newer to build and install, though the README notes the generated code has lower requirements.

```sh
go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
oapi-codegen -version
```

The README recommends managing the dependency with Go's tool support rather than a global binary, so the generator version travels with the application's go.mod. That command modifies go.mod and adds a tool directive.

```sh
go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
```

Once it is a tool dependency, generation is wired into go generate, which is the pattern the README shows. The example points at a config file and a spec two directories up.

```go
//go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml
```

The README documents configuration through a YAML file and ships a configuration-schema.json at the repository root, so your editor can validate the keys you write. The README's own example config is not reproduced here; the keys you set there decide the package name and which pieces are emitted. Running the generate step should leave a new .go file beside your config, containing the types and client derived from the specification. The README also covers pinning to commits if you would rather not track @latest, and generating from HTTPS paths or inline templates when the default templates do not fit.

## Where oapi-codegen gets in your way

The generated code is deliberately plain, and plain means large. A specification with a few dozen schemas produces a file that dwarfs the hand-written code around it. The README's own FAQ asks whether you should commit the generated code and whether you should lint it, which is an admission that both questions come up constantly and that the answers are not obvious.

Version coupling is the sharper problem. The project depends on kin-openapi, and the README has a FAQ entry for people who upgraded kin-openapi and found their build broken. If your application also imports kin-openapi directly, the version oapi-codegen expects and the version you want can diverge, and the generated code is what breaks.

Security has been an active area rather than a settled one. Three recent releases are relevant: v2.7.1 is titled as a security fix for Go code injection, v2.7.2 is described as more fixes for code injection issues, and v2.8.0 is described as OpenAPI 3.1 support, fewer assumptions, and a large bug hunt. If you are pinned to an older release, that sequence is a reason to move.

Finally, this is not a validation framework. The README documents request and response validation middleware as something you add, not something the generator installs for you. Teams expecting the generated server to reject malformed requests out of the box will be surprised.

## oapi-codegen versus OpenAPI Generator and go-swagger

OpenAPI Generator is the obvious alternative, and the difference is scope. It targets many languages and many frameworks, so a Go service is one output among dozens and the Go templates carry abstractions that exist to keep the generator general. oapi-codegen targets Go only. That focus is why its output reads like Go rather than like a translation of a language-neutral template, and it is also why it cannot help a polyglot repository that wants one generator for TypeScript, Python and Go.

go-swagger takes a different route again. It is a broader toolkit around Swagger specifications, and the comparison people search for is usually about which generates the server shape they want. The practical distinction is the specification version and the output philosophy: oapi-codegen is built around OpenAPI 3.0 and 3.1 and around generating code you then own, while go-swagger carries more of its own runtime conventions.

If your team writes Go and nothing else, the single-language focus is a benefit. If your API is consumed by a mobile client, a frontend and a service mesh, one generator producing idiomatic output in one language does not solve the other three.

## Maintenance, licensing and the upgrade path

The repository is not archived, and the last push was on 2026-09-18. Releases have been frequent through 2026, including v2.8.0 on 2026-07-17, v2.7.2 on 2026-07-07 and v2.7.1 on 2026-06-05. The issue that should shape your upgrade policy is the pair of code injection fixes in v2.7.1 and v2.7.2. Treat the generator as a build-time tool that processes untrusted input, because a specification can come from another team or a vendor.

The licence is Apache-2.0. That is permissive and includes an explicit patent grant, which matters to organisations that care about that clause. It is not legal advice, and the generated output sitting in your repository is a question for your own counsel, not for the README.

Upgrade cost is dominated by two things: the import path change from the Deepmap organisation, and the kin-openapi dependency. The README gives the exact recursive replacement, from github.com/deepmap/oapi-codegen/v2 to github.com/oapi-codegen/oapi-codegen/v2, and warns that the move landed with v2.3.0. Projects still on v2.2.0 or below need that edit before they can take any newer release. Because generation is usually wired into go generate or a Makefile target, the upgrade itself is mechanical; what takes time is reviewing the regenerated diff.

## Splitting a large specification without duplicating types

One specification per repository gets unwieldy. oapi-codegen addresses this with import mapping, which the README also calls external references. The mechanism is a mapping from a specification's reference to a Go package, so a type defined in one document is imported from the package generated for that document rather than redefined.

The README describes two shapes. You can keep a single package and feed it multiple OpenAPI specs, which keeps imports short but means one package holds everything. Or you can use multiple packages with one spec per package, which gives real boundaries between services at the cost of a mapping table to maintain.

The trade-off is real and the README does not pretend otherwise. Multiple packages mean the import map has to be updated whenever a spec moves, and a mistake shows up as a compile error in generated code rather than a clear message from the generator. The single-package approach avoids that bookkeeping but gives up the boundary. For a monorepo with several services sharing a few schemas, the multi-package route is the one that stays readable as the schemas grow.

There is also OpenAPI Overlay support for modifying the input specification before generation, which is the right tool when a vendor's document needs a local adjustment and you would rather not fork it.

## Conclusion

Adopt oapi-codegen if your API contract lives in an OpenAPI document and you want Go code you can read, review and commit. Skip it if you need generated code in several languages, or if you expect the tool to run validation for you without wiring the middleware in. Before committing, generate against your own spec, check how anyOf, allOf and oneOf come out, and confirm the generated module's Go version against the servers you deploy to.

## FAQ

### How do I install oapi-codegen?

Install it from the current module path with go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest, or add it as a tool dependency with go get -tool. The README recommends the tool dependency so the generator version is managed alongside your application. Building and installing requires Go 1.25 or newer.

### What is oapi-codegen used for?

It converts OpenAPI 3.0 and 3.1 specifications into Go code: HTTP models, API clients and server-side boilerplate. The README frames the goal as reducing the boilerplate needed to create or integrate with OpenAPI-based services so you can spend time on business logic.

### How do I use oapi-codegen?

You run the command against a specification, usually with a config file that sets the package name and which pieces to generate. The README shows wiring it into go generate with a directive such as go tool oapi-codegen -config cfg.yaml ../../api.yaml, so regeneration happens as part of the normal build workflow.

### How does oapi-codegen compare with go-swagger?

oapi-codegen is built around OpenAPI 3.0 and 3.1 and generates Go code you then own, while go-swagger carries more of its own runtime conventions. The README does not offer a feature-by-feature comparison, so the practical test is generating from your own specification with each tool and reading the output.

### What are alternatives to oapi-codegen?

OpenAPI Generator is the main alternative and targets many languages and frameworks, so a Go service is one output among many. That breadth is the difference in approach: oapi-codegen is Go-only, which is why its generated code reads like hand-written Go rather than a language-neutral template.

## Sources

- [Issues](https://github.com/oapi-codegen/oapi-codegen/issues)
- [License: Apache-2.0](https://github.com/oapi-codegen/oapi-codegen/blob/main/LICENSE)
- [oapi-codegen/oapi-codegen on GitHub](https://github.com/oapi-codegen/oapi-codegen)
- [README](https://github.com/oapi-codegen/oapi-codegen/blob/main/README.md)
- [Releases](https://github.com/oapi-codegen/oapi-codegen/releases)

---

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