emicklei/proto: a Go parser for .proto files that hands you a tree, not an error
parser for Google ProtocolBuffers definition
At a glance
- What is it?
- emicklei/proto parses Protocol Buffers definitions into a navigable Go tree with a visitor pattern, so tooling can read a schema and act on it. The README is explicit that the parser does not fully validate, which makes it a building block for linters and generators rather than a compiler.
- Who is it for?
- emicklei/proto fits Go developers building schema tooling, documentation generators, or linters that need to read a .proto file as structured data rather than as text, and it is a small library with an MIT licence and a long history of use. It is the wrong tool if you need validation, because the README states the parser is not a complete validator and points you at protoc or a linting tool for that job.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 76 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The library parses a schema so other tools can act on it
emicklei/proto is a Go package for parsing Google Protocol Buffers .proto files, covering version 2 and 3 syntaxes and editions. It is not a protobuf runtime and it does not generate code. It is a parser that turns a schema definition into a tree of Go structures that your own program can walk. That distinction matters for who should reach for it. If you want to serialise and deserialise messages, you want a runtime library. If you want to build a linter, a documentation generator, a schema diffing tool, a migration planner, or anything that reads a .proto file and reasons about its contents, this is the layer you need. The repository is organised around exactly that, with separate source files for each grammatical element, and the author's related projects are in the same family, including protofmt, proto2xsd, and proto2gql.
Install is one go get and the module has no dependencies
Installation is the standard Go toolchain path:
go get github.com/emicklei/protoThe `go.mod` file declares the module as `github.com/emicklei/proto` with `go 1.12` and nothing else, which means the package pulls in no third-party dependencies of its own. That is a meaningful property for a library that sits inside a build or lint pipeline, where every transitive dependency is another thing to track and another licence to review. The README links a GoDoc badge to pkg.go.dev, so the API documentation is generated from the source, and a codecov badge tracks test coverage across the branch.
The parse tree is walked with a visitor, not queried by hand
The usage example in the README shows the shape of the API. You open a file, hand the reader to `proto.NewParser`, call `parser.Parse()` to get a definition, and then walk it:
parser := proto.NewParser(reader)
definition, _ := parser.Parse()
proto.Walk(definition,
proto.WithService(handleService),
proto.WithMessage(handleMessage))`proto.Walk` takes the definition and a set of options, and the options are visitors for the node types you care about. The visitor pattern here is the whole design. You implement a handler for services and one for messages, and the walk calls them as it encounters matching nodes. The repository has a `noop_visitor.go`, which is the extension point for cases where you only want to look at one element type and do not want to implement every method, and a `visitor.go` holding the interface itself.
Every element in a schema has its own node type
The repository layout is the API documentation. Separate files exist for each grammatical element of a .proto file: `message.go`, `enum.go`, `field.go`, `oneof.go`, `group.go`, `service.go`, `option.go`, `package.go`, `import.go`, `extensions.go`, `reserved.go`, `syntax.go`, `literals.go`, `range.go`, `edition.go`, `comment.go`, and `parent_accessor.go`. Each of those is a struct you can receive in a visitor. The `parent_accessor.go` file exists because a visitor that only receives a node still needs to walk upwards, and `comment.go` exists because comments are attached to elements and are usually the first thing you want when generating documentation. Two files are worth singling out for anyone writing a linter. `range.go` covers the repeated range syntax used in reserved declarations, and `literals.go` handles the literal value forms that appear in options and in default values.
The visitor can be extended to reach options inside a message
The example goes one level deeper than the node types, because the interesting part of a message is often in its options. The README's `handleMessage` function takes each element of `m.Elements` and calls `Accept` on it with a visitor that embeds `proto.NoopVisitor` and overrides only `VisitOption`:
type optionLister struct {
proto.NoopVisitor
}
func (l optionLister) VisitOption(o *proto.Option) {
fmt.Println(o.Name)
}Embedding the no-op visitor means you implement one method and inherit a do-nothing implementation for the rest of the interface. This is the pattern to follow if you want to inspect custom options such as field behaviour annotations, or the `deprecated` and `packed` flags, without writing a full visitor per message type. It is also the pattern that makes the library composable: a linter can be written as a set of small visitors, each doing one check, all applied in a single walk.
The parser does not validate, and the README says so
This is the limitation to internalise before you build on the library. The README has a section on validation and states that the current parser implementation is not completely validating .proto definitions, and that in many but not all cases it will report syntax errors when reading unexpected characters or tokens. The recommendation is to use some linting tools or protoc for full validation. So the parser is a lexer-and-tree builder, not a schema checker. It will happily give you a tree for a schema that protoc would reject. That is fine for tooling that needs to read what is there, and wrong for tooling that needs to prove the schema is correct, and it explains why the author recommends protoc alongside this package rather than instead of it. It also means a rule that only fires on well-formed input needs its own guard, since the tree may be incomplete when the source had errors.
A Makefile shows how the project is linted, and what is currently off
The Makefile documents the project's own quality process, which is worth reading because it shows where the maintainer places trust. `make install` runs `go install./...`, `make vet` runs `go vet./...`, and `make test` runs the test suite with the race detector and a coverage profile in atomic mode. The default goal runs `lint` and `test`. The lint target is currently `golint vet`, and the file contains TODO comments noting that errcheck and staticcheck will be readded when fixed, with the commented-out lines showing the fuller `golint vet errcheck staticcheck` combination that existed before. Each tool is pinned to an exact version or commit hash, golint to a commit, errcheck to v1.2.0, and staticcheck to a commit, and they are installed into a temporary bin directory keyed by OS and architecture. The staticcheck invocation disables the U1000 check set. A `CHANGES.md` at the root tracks changes, and the repository has no GitHub releases, so version history lives in the module proxy and the changelog rather than in tags.
MIT licensed, still receiving commits, and small enough to read
The licence is MIT, and the README carries the copyright line for 2017 to 2025 with a note that contributions are welcome. The last push was on 2026-08-08, which puts the project in recent-but-not-frantic territory: it is being worked on, and the maintainer is not shipping releases. What makes this package pleasant to adopt despite that is its size. The root directory is a flat list of focused files, each with a matching test file, and there is no internal package hierarchy to navigate. When a library is this small, reading the source is a reasonable alternative to reading the documentation, and you can see exactly how a node type is represented. The `go.mod` declaring go 1.12 is the other signal worth noting, since it means the code compiles against a very old toolchain baseline and will not force a toolchain upgrade on the project that depends on it.
Editorial conclusion
emicklei/proto fits Go developers building schema tooling, documentation generators, or linters that need to read a .proto file as structured data rather than as text, and it is a small library with an MIT licence and a long history of use. It is the wrong tool if you need validation, because the README states the parser is not a complete validator and points you at protoc or a linting tool for that job. Before adopting it, decide whether you want the parse tree or a diagnostic, because this package gives you the former, and read the Makefile targets before you rely on the linting setup, since the errcheck and staticcheck steps are currently commented out.
Frequently asked questions
How do I install emicklei/proto?
The README gives a single command, `go get github.com/emicklei/proto`. The module declares `go 1.12` and lists no third-party dependencies.
Does emicklei/proto validate .proto files?
Not completely. The README states that the current parser implementation is not completely validating .proto definitions, and that in many but not all cases it reports syntax errors for unexpected characters or tokens. It recommends using linting tools or protoc for full validation.
How do I walk the parsed proto definition in emicklei/proto?
You call `proto.Walk` with the definition and visitor options such as `proto.WithService` and `proto.WithMessage`. A visitor can embed `proto.NoopVisitor` and override only the methods it needs, for example `VisitOption` to inspect options inside a message.
Which .proto syntax versions does emicklei/proto support?
The package is described as parsing .proto files version 2 and 3, along with editions, and the repository contains a separate `edition.go` source file alongside `syntax.go`.
What related tools exist for emicklei/proto?
The README points to the proto-contrib repository for contributions built on top of the package, such as protofmt, proto2xsd, and proto2gql, and to protobuf2map, a small package for inspecting serialized protobuf messages using a .proto definition.
What licence is emicklei/proto under?
MIT, with the LICENSE file at the repository root and the copyright line covering 2017 to 2025. The repository has no GitHub releases, and the last push was on 2026-08-08.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/emicklei-proto)Was this useful?