# Goa: a design-first Go framework that generates HTTP, gRPC and JSON-RPC from one contract

> Goa generates server code, clients, a CLI and OpenAPI/protobuf specs from a Go design package, so the contract and the implementation cannot drift apart. It suits Go teams shipping more than one transport; it is the wrong tool if you want to hand-write your routing.

**goadesign/goa** — Design-first Go framework that generates API code, documentation, and clients. Define once in an elegant DSL, deploy as HTTP and gRPC services with zero drift between code and docs.

- Repository: https://github.com/goadesign/goa
- Website: https://goa.design
- Stars: 6,111 · Forks: 582
- Language: Go
- License: MIT
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/goadesign-goa

## The problem Goa solves: one contract, three transports

A Go service that speaks HTTP and gRPC usually carries the same description twice. The HTTP handler decodes a path parameter and validates it; the gRPC method decodes a protobuf message and validates the same rule again; a third copy lives in the OpenAPI file that nobody regenerates after the last change. Goa removes the copies by making the design the source. Types, methods, validation rules and errors are declared once in a Go package under design/, and the generator emits the transports, their Go clients, a CLI client, OpenAPI specifications and Protocol Buffer definitions from it.

The README states the intended audience plainly: it is written for teams whose coding agent does the implementation work. The argument is token economics rather than elegance. Routing, serialization, validation and clients are mechanical, so the generator writes them and the agent spends its context on requirements, business rules and tests. That framing is a real design constraint, not marketing: the repository ships a skills/ directory and an AGENTS.md file, and the README instructs you to install a service-designer skill into your own repository before handing the agent a task.

If you already hand-write handlers and consider generated routing an imposition, Goa's premise does not apply to you. The whole value proposition depends on accepting that design/ is the authority and gen/ is disposable output.

## How the generator pipeline works from design to gen

The design package imports the DSL with a dot import, so the declarations read as a small configuration language rather than as Go function calls. A Service block names the service and can attach transport-level settings such as a JSON-RPC endpoint. A Method block declares the payload, the result and the transport bindings. The README's example declares one method with a single required string field, then binds it to GET /hello/{name} for HTTP, to an empty GRPC block, and to a JSON-RPC block.

Generation is a two-command split, and the distinction matters. The gen subcommand replaces the generated tree, so anything you put under gen/ is lost on the next run. The example subcommand creates missing application files and leaves existing ones alone. That is the mechanism the README leans on to keep your work safe: implement outside gen/, and the regeneration cycle cannot overwrite you.

The transports all call one generated service interface. In the README's walkthrough the implementation is a struct with a Greet method that takes a generated payload type and returns a string. Validation lives in the generated transport, so an empty name is rejected before Greet runs. Adding a field or changing a rule means editing the design and regenerating, and because the generated interface changes, the Go compiler points at the implementations and callers that need updating. That compiler-driven step is the part that makes the workflow hold up over time.

## Installing goa and running a first service

The README asks for Go 1.26 or later and recommends Go 1.27.1, which matches the go 1.26.0 directive in the repository's go.mod. Start by creating a module, fetching the framework and making a place for the design package. The module path is versioned, so the import carries the /v3 suffix.

```bash
mkdir hello && cd hello
go mod init hello
go get goa.design/goa/v3@latest
mkdir design
```

Save the greeting design as design/design.go. For an HTTP-only first run, the README says to omit the JSONRPC blocks and the GRPC block; keeping all three requires the Protocol Buffer compiler and the Go protobuf generators, which UPGRADING.md covers. Then generate the code and the starter application. The first command writes the generated tree; the second fills in the application files that are missing.

```bash
go mod tidy
go run goa.design/goa/v3/cmd/goa gen hello/design
go run goa.design/goa/v3/cmd/goa example hello/design
```

Replace the starter hello.go with your own implementation, keeping it outside gen/, then build and run. The port is passed as a flag on the generated command.

```bash
go mod tidy
go run ./cmd/hello --http-port=8000
```

In another terminal, the README's curl call returns the greeting for the name in the path.

```bash
curl http://localhost:8000/hello/Alice
# "Hello, Alice!"
```

If you kept all three transports, the generated CLI reaches the same method over each of them. The HTTP form uses a URL flag and a name flag; the gRPC form uses a grpc:// URL with a JSON message; the JSON-RPC form adds a --jsonrpc flag and passes a body. All three return the same string, which is the clearest demonstration that one design produced three callable surfaces.

## Where the generated tree gets in your way

The gen/ directory is not a cache you can patch. The README states that gen replaces the generated tree, so a hand edit there survives until the next invocation and no longer. Teams that are used to adjusting generated code to fit an existing router will find that constraint harder to accept than the DSL itself. The workable pattern is the one the README describes: change design/, regenerate gen/, implement outside it.

There is a second, quieter cost. The design package is Go, which means the DSL is checked by the compiler and you get autocompletion, but it also means the contract is not readable by anyone who does not read Go. A team that wants a language-neutral contract file, reviewable by people outside the Go codebase, is choosing the wrong shape here.

Transport coverage is declared per method, so a service with mixed requirements needs the blocks spelled out rather than inferred. The README's example carries HTTP, GRPC and JSONRPC blocks on the same method; the note that you can drop the gRPC and JSON-RPC blocks for an HTTP-only run implies the converse, that nothing is generated for a transport you do not declare.

Finally, the gRPC and JSON-RPC paths pull in a protobuf toolchain. The go.mod lists google.golang.org/grpc v1.84.0 and google.golang.org/protobuf v1.36.12, and the Makefile installs protoc-gen-go and protoc-gen-go-grpc as build dependencies. That is more setup than an HTTP-only project needs, and the README routes readers to UPGRADING.md for the install steps rather than spelling them out in the quickstart.

## Goa against hand-written routers and OpenAPI-first generators

The obvious alternative is a conventional Go router such as chi. Goa's own go.mod depends on github.com/go-chi/chi/v5 v5.3.2, so the comparison is not abstract: Goa generates code that sits on top of a router rather than replacing the idea of one. With chi alone you write the handler, decode the request, validate the fields and maintain the OpenAPI document separately, and you keep full control over middleware order and route shapes. With Goa you describe the operation and let the generator produce the binding, which is why the generated transports reject an invalid payload before your method is called. The trade is control for consistency.

A different alternative is an OpenAPI-first generator, where the specification file is the source and the server stubs are produced from it. Goa inverts that: the Go design package is the source and the OpenAPI document is an output, alongside protobuf definitions. If your organization already reviews API changes as specification diffs, the OpenAPI-first route matches that process. If your reviewers read Go and your services are Go, Goa's direction removes the separate editing step.

The repository also points at goadesign/goa-ai for building AI agents, and ships a skills/ directory with installation options beyond the npx command. Those are adjacent projects, not substitutes, and the README treats them as part of the same design-first workflow.

## Maintenance, licensing and what a version bump costs

The repository is not archived and the last push was on 2026-09-21. Releases are frequent and recent: v3.32.0 on 2026-09-21, v3.31.1 on 2026-09-16, v3.31.0 on 2026-09-16. The v3.31.1 release note describes the generation preview as stable, and the Makefile carries explicit preview targets (prepare-preview, release-preview) alongside the regular release targets, which tells you previews are a deliberate channel rather than an accident.

The project is MIT licensed, which places few obligations on how you redistribute or modify it. That is a statement about the licence text, not advice about your situation; if you vendor the generator or ship generated code under your own terms, read LICENSE and your own policy.

Upgrade cost concentrates in the generated tree, which is the point of the design. Because gen/ is rewritten, a framework upgrade that changes code generation does not leave stale artifacts behind. What it does leave is compile errors in your implementation where a generated interface changed, and that is the intended signal. The repository keeps an UPGRADING.md at the top level for the steps that are not automatic, including the protobuf generator install for v3.32.0. The Makefile is the maintainer's entry point, not yours: depend, lint, test and integration-test are the targets that gate a release, and they assume a Go toolchain plus golangci-lint.

## Conclusion

Teams that expose the same operations over HTTP and gRPC, and that already treat Go as their implementation language, get the most from Goa: the design package is the single place where types, validation and errors are declared, and the generator keeps the specs aligned with it. Do not adopt it if your routes are hand-tuned per endpoint or you cannot accept a generated tree that is rewritten on every run. Before committing, verify that your Go toolchain satisfies the go 1.26.0 directive in go.mod, that you are willing to keep implementation code outside gen/, and that the protobuf toolchain is installed if you want the gRPC and JSON-RPC transports rather than HTTP alone.

## FAQ

### What is Goa in the context of Go development?

Goa is a design-first Go framework that generates HTTP, gRPC and JSON-RPC APIs from a single contract. You describe types, operations and validation in a Go design package, and the generator produces the server code, clients, a CLI and OpenAPI/protobuf specifications.

### How do I install goa and generate a first service?

Create a module, run go get goa.design/goa/v3@latest, and add a design package. Then run go run goa.design/goa/v3/cmd/goa gen hello/design to generate the code and go run goa.design/goa/v3/cmd/goa example hello/design to create the starter application files.

### Which Go version does Goa require?

The README asks for Go 1.26 or later and recommends Go 1.27.1. The repository's go.mod declares go 1.26.0.

### Does Goa generate gRPC and JSON-RPC as well as HTTP?

Yes, when the design declares them. The README's example service exposes the same greeting over HTTP, gRPC and JSON-RPC, and the generated CLI can call the method over each transport. An HTTP-only first run can omit the GRPC and JSONRPC blocks.

### Does regenerating Goa code overwrite my implementation?

The gen subcommand replaces the generated tree, so code under gen/ is lost on the next run. The example subcommand only creates missing application files and leaves existing ones alone. The README's guidance is to keep your implementation outside gen/.

## Sources

- [goadesign/goa on GitHub](https://github.com/goadesign/goa)
- [License: MIT](https://github.com/goadesign/goa/blob/v3/LICENSE)
- [Project website](https://goa.design)
- [README](https://github.com/goadesign/goa/blob/v3/README.md)
- [Releases](https://github.com/goadesign/goa/releases)

---

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