go-flags
A reflection-based command-line option parser for Go that turns struct field tags into fully documented flags, subcommands, and INI-file configuration.
Repository Health
Technical Analysis
go-flags is a command-line argument parsing library for Go that goes well beyond the standard library’s flag package. Instead of imperatively registering each flag, you declare a plain Go struct and annotate its fields with tags such as short, long, description, default, env, and required; the library uses reflection to turn that struct into a fully-featured parser, including generated --help output.
Beyond basic flags, go-flags supports nested option groups, namespaced sub-parsers, git-style subcommands (with aliases and arbitrarily deep nesting), positional argument structs, maps and slices as option values, custom types via the Marshaler/Unmarshaler interfaces, and reading defaults from environment variables or an INI file. It also ships a builtin shell-completion mode and Windows-style /flag option syntax as an alternative to POSIX-style dashes.
The project has been stable for over a decade (created in 2012, BSD-3-Clause licensed) and is widely vendored as a dependency inside other popular Go CLIs and tools, making it one of the more battle-tested alternatives to spf13/cobra and spf13/pflag for teams that prefer a struct-tag-driven, declarative style over an imperative builder API.
What You Get
- Declarative struct-tag API — short (
-v) and long (--verbose) option names, descriptions, defaults, and required flags all defined as Go struct tags instead of imperative registration calls - Automatic, well-formatted
--helpand man-page generation derived directly from the same struct tags used for parsing - First-class subcommand support (
AddCommandor acommand:struct tag) with aliases, arbitrary nesting, and aCommanderinterface for wiring upExecutehandlers - Rich value support: slices (repeatable flags), maps (
key:valuesyntax), pointers, function callbacks, and choice-restricted string enums via thechoicetag - Configuration layering — flag values can default from environment variables (
envtag, withenv-delimfor slices/maps) or be read from and written to INI files - Built-in bash completion mode (
GO_FLAGS_COMPLETION=1) with aCompleterinterface for custom value completion, plus Windows-style/flagsyntax as a build-time alternative to POSIX dashes
Common Use Cases
- Building a single-binary CLI tool that needs typed, validated flags (ints, durations, custom types) without hand-writing conversion and validation code
- Building git-style multi-command CLIs (
mytool add,mytool rm) where each subcommand has its own option set plus inherited parent flags - Tools that need to support configuration from multiple sources — command line, environment variables, and an INI config file — with a single struct as the source of truth
- CLIs that need to ship shell completion (bash) for flags, subcommands, and argument values without maintaining a separate completion script generator
- Projects standardizing on a struct-tag/reflection style of flag definition instead of
pflag’s imperativeVar-style registration
Under The Hood
Architecture
go-flags is organized as a layered set of cooperating types rather than a monolith: Parser (in parser.go) embeds *Command (in command.go), which embeds *Group (in group.go), so a parser is itself the root command and root group — this lets subcommands (also *Command) recursively contain their own groups and further subcommands with no special-casing. Each declared struct field becomes an Option (option.go) built from a multiTag (multitag.go), a small hand-rolled tag-string scanner independent of reflect.StructTag.Lookup. Parsing walks the args slice consuming short/long options and dispatching into the active Command’s options, sub-Groups, or a matched subCommand, so the core abstraction that would break the whole design if changed is the Group/Command/Option embedding chain — every feature (namespaces, INI I/O, help/man generation, completion) reads from that same tree rather than a separate flag registry.
Tech Stack
The library targets Go 1.20 and has exactly two runtime dependencies: golang.org/x/sys (for terminal width detection used by termsize.go’s platform-specific termsize_windows.go/termsize_nosysioctl.go files) and github.com/sergi/go-diff (used only in tests, for diffing expected vs. actual help output). Everything else — INI parsing (ini.go), man-page generation (man.go), bash completion (completion.go), and its own Levenshtein-distance implementation for “did you mean” suggestions (closest.go) — is hand-written rather than pulled in from third-party packages, keeping the dependency footprint minimal for a library meant to be vendored into many other CLIs.
Code Quality
The repository is unusually thoroughly tested for its size: 16 _test.go files sit alongside roughly 20 non-test .go files, with dedicated suites for parser behavior, help/man output, INI round-tripping, completion, commands, groups, and short/long option edge cases. CI (.github/workflows/) runs go build, go test -v ./..., gofmt -l (fails on unformatted files), and go vet across Ubuntu, Windows, and macOS runners, so cross-platform behavior (notably the Windows /flag option style) is exercised on every push. Errors are represented as a typed Error with an ErrorType enum (error.go) rather than ad hoc string errors, giving callers a way to branch on failure kind (e.g. ErrRequired, ErrTag).
What Makes It Unique
Relative to imperative Go flag libraries, go-flags’ distinguishing choice is deriving the entire parser — names, defaults, required-ness, environment fallback, INI serialization, and generated help — from a single struct definition via reflection and tags, rather than a builder API where each of those concerns is registered separately and can drift out of sync. Its command/group embedding lets subcommands, nested namespaces, and INI configuration compose through the same tree instead of bolt-on subsystems, and it includes conveniences (typo-suggestion via Levenshtein distance, Windows-style /flag syntax, built-in man-page generation) that most comparable libraries leave to the application author.
Used by 2 apps in this directory
Netdata
Monitoring · Devops
Real-time per-second metrics, ML-powered anomaly detection, and zero-config observability for any infrastructure.
Weaviate
Databases · Search
Open-source vector database combining semantic search, hybrid queries, RAG, and image search in a single cloud-native system built for production scale.