Updated Nov 5, 20266 min read

Swagger and OpenAPI in Go: swag, go-swagger, oapi-codegen, ogen and Huma

How Go teams get an OpenAPI spec and Swagger UI for their APIs in 2026. Annotation-based generation with swag, spec-first code generation with oapi-codegen and ogen, code-first frameworks like Huma, where go-swagger fits now, and how to pick between them.

People searching "go swagger" usually want one of two things: interactive Swagger UI docs for an existing Go API, or a way to keep an OpenAPI spec and Go handlers in sync. The Go ecosystem has three approaches: annotation tools read comments and produce a spec, spec-first generators turn a YAML file into Go interfaces, and code-first frameworks derive the spec from typed handlers. Each makes a different part of the API the source of truth, and that choice decides how much drift you will fight later.

The Go OpenAPI tools at a glance

ToolApproachSpec versionLatest release (Nov 2026)
swaggo/swagComments to specSwagger 2.0 in v1, OpenAPI 3.1 in v2 release candidatesv2.0.0-rc6
go-swaggerSpec to code, code to specSwagger 2.0 onlyv0.36.7
oapi-codegenSpec to codeOpenAPI 3.0 and 3.1v2.8.2
ogenSpec to codeOpenAPI 3v1.24.0
HumaCode to specOpenAPI 3.1v2.40.0

Annotation-based: swag

swag is the most popular option, with about 13,000 GitHub stars. You annotate handlers with structured comments, run swag init, and it writes a docs package containing swagger.json, swagger.yaml and a Go file that registers the spec:

// GetUser godoc // @Summary Get a user // @Description Returns one user by ID. // @Tags users // @Produce json // @Param id path int true "User ID" // @Success 200 {object} User // @Failure 404 {object} ErrorResponse // @Router /users/{id} [get] func GetUser(w http.ResponseWriter, r *http.Request) { // ... }

Swagger UI is then served with middleware such as http-swagger for net/http or gin-swagger for Gin. It works with any existing router. The cost is that the annotations are a second description of the handler, written by hand: rename a field or change a status code and the spec stays wrong until someone updates the comment. Version 1 also produces Swagger 2.0, which some newer tooling handles poorly. The v2 line, still a release candidate after more than a year, adds OpenAPI 3.1 output behind a --v3.1 flag.

go-swagger: still Swagger 2.0

go-swagger generates servers and clients from a Swagger 2.0 spec and can also produce a spec from annotated code. It is actively maintained, with a release at the end of October 2026, but its README states it does not support OpenAPI 3.x. It suits teams with an existing Swagger 2.0 contract. New projects that want OpenAPI 3 features such as oneOf, webhooks or JSON Schema alignment should look at the next two groups.

Spec-first: oapi-codegen and ogen

With a spec-first workflow, the OpenAPI YAML file is the contract. It is reviewed like code, and the generator produces Go types and a server interface that your handlers must satisfy, so the compiler catches drift.

oapi-codegen supports OpenAPI 3.0 and 3.1 and generates server code for net/http, Chi, Echo, Gin, Fiber and others, including a "strict" mode where handlers receive typed request objects and return typed responses. ogen generates both client and server, with its own router and JSON encoding that avoid reflection.

This approach fits public APIs, APIs shared with other teams, and organizations that review the contract before implementation. The cost is that every change starts in YAML, and the YAML for a large API becomes a large file to maintain.

Code-first: Huma

Huma inverts the flow: you register operations with typed Go input and output structs, using struct tags for validation and docs, and Huma generates an OpenAPI 3.1 spec and JSON Schemas at runtime. It sits on top of routers such as Chi, Gin, Echo or net/http. The spec cannot drift because it is derived from the same types the handler uses, and validation comes from the same struct tags.

Which approach to pick

  • Existing API, docs needed this week: swag. Expect to maintain the annotations.
  • Contract shared with customers or other teams: spec-first with oapi-codegen.
  • One team owns the API and its clients: code-first, where the handler types are the spec.

Generating the spec from Go doc comments with Encore

Encore

Encore is a tool that works alongside your framework for TypeScript and Go, with a platform that provisions and deploys into your own AWS or GCP account. It takes the code-first approach further: the endpoint signature and request and response types are parsed at compile time, and ordinary Go doc comments become the documentation, so there is no annotation syntax to learn. The API documentation guide covers where each comment ends up.

Set up the app

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

~
$ encore app create users-api --example=go/hello-world$ cd users-api && mkdir users
// Package users manages user accounts. package users import ( "context" "errors" "encore.dev/beta/errs" "encore.dev/storage/sqldb" ) var db = sqldb.NewDatabase("users", sqldb.DatabaseConfig{ Migrations: "./migrations", }) // User is a registered account. type User struct { // ID is the unique user identifier. ID int64 `json:"id"` // Email is the user's login address. Email string `json:"email"` } // Get returns one user by ID. // It returns NotFound if no user has the given ID. // //encore:api public method=GET path=/users/:id func Get(ctx context.Context, id int64) (*User, error) { u := &User{ID: id} err := db.QueryRow(ctx, `SELECT email FROM users WHERE id = $1`, id).Scan(&u.Email) if errors.Is(err, sqldb.ErrNoRows) { return nil, &errs.Error{Code: errs.NotFound, Message: "user not found"} } else if err != nil { return nil, err } return u, nil }
-- users/migrations/1_create_users.up.sql CREATE TABLE users (id BIGSERIAL PRIMARY KEY, email TEXT UNIQUE NOT NULL);

With encore run running, which starts Postgres locally, generate the spec:

~/users-api
$ encore gen client --lang=openapi --output=./openapi.json

The first line of the endpoint comment becomes the OpenAPI summary, the remaining lines the description, and the type and field comments land in the schemas. OpenAPI output is marked experimental in the client generation docs, and the --openapi-exclude-private-endpoints flag leaves internal endpoints out of a spec you publish. The same metadata drives typed TypeScript and Go clients and the API explorer in the local development dashboard, which fills the role Swagger UI plays during development.

An AI coding agent that changes an endpoint sees the doc comment in the same edit and can update both, and the regenerated spec reflects the change with no separate annotation file to forget. Deploying the app creates the database and services in your AWS or GCP account, as covered in the AWS infrastructure docs.

The Infrastructure page in the Encore dashboard with a database's configuration panel open, showing fields for vCPUs, memory, storage, availability type, max connections and backups.
Each provisioned resource can be reviewed and its configuration edited per environment in the Encore dashboard. The screenshot shows a GCP Cloud SQL database.

Best fit: Go teams that own both the API and its clients and want an accurate OpenAPI spec derived from their endpoint types.

Frequently asked questions

How do I add Swagger to a Go API?

The most common way is swaggo/swag: write @Summary, @Param, @Success and @Router annotations above each handler, run swag init to generate a docs package with swagger.json and swagger.yaml, and serve Swagger UI with the http-swagger or gin-swagger middleware. Version 1 generates Swagger 2.0, and the v2 release candidates add OpenAPI 3.1 output behind the --v3.1 flag.

Does go-swagger support OpenAPI 3?

No. go-swagger implements Swagger 2.0, also called OpenAPI 2.0, and its README states it does not support OpenAPI 3.x. For OpenAPI 3.0 and 3.1, use oapi-codegen or ogen for spec-first generation, or Huma for code-first.

Should I write the OpenAPI spec first or generate it from Go code?

Write the spec first when other teams or customers consume the API and the contract needs review before implementation, using oapi-codegen or ogen to generate the Go server interfaces. Generate it from code when one team owns both sides and the spec is mainly documentation, so the spec cannot drift from the handlers.

How do I generate an OpenAPI spec from an Encore Go app?

Write doc comments above your //encore:api endpoints and request and response types, then run encore gen client --lang=openapi --output=./openapi.json while the app runs locally. The first line of each endpoint comment becomes the OpenAPI summary and the rest becomes the description.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders