flags is a reflection-powered command-line parser for Go.
It lets you describe a CLI with ordinary Go structs and tags,
then handles parsing, help, completion, configuration, validation,
localization, and generated documentation around that model.
It keeps the familiar struct-tag workflow, while adding stricter validation, better generated output, modern completion/docs tooling, and practical integration APIs.
Documentation Site · Go Reference
Use flags when you want a CLI that is defined close to the Go data it fills.
The struct remains the public contract, and the parser can derive help,
completion, config examples, and documentation from the same source.
Useful strengths:
- short and long options with POSIX-style parsing;
- commands, subcommands, option groups, and positional arguments;
- typed values, defaults, slices, maps, counters, and custom parsers;
- environment variables, .env file and JSON/INI configuration;
- value validators for common string, path, and numeric constraints;
- shell completion for bash, zsh, and PowerShell;
- generated help, markdown, HTML, and manpage output;
- opt-in localization for parser text and user-facing metadata;
- runtime setters for generated or application-owned metadata.
go get github.com/woozymasta/flagspackage main
import (
"errors"
"fmt"
"os"
"github.com/woozymasta/flags"
)
type Options struct {
Verbose bool `short:"v" long:"verbose" description:"Show verbose output"`
Name string `short:"n" long:"name" required:"true" description:"User name"`
}
func main() {
var opts Options
parser := flags.NewParser(&opts, flags.Default)
_, err := parser.Parse()
if err != nil {
var ferr *flags.Error
if errors.As(err, &ferr) && ferr.Type == flags.ErrHelp {
os.Exit(0)
}
os.Exit(1)
}
if opts.Verbose {
fmt.Println("verbose mode enabled")
}
fmt.Printf("hello, %s\n", opts.Name)
}Run it:
app --name Alice
app -v --name Alice
app --helpflags.Default enables the built-in help flag,
parser error printing, and -- pass-through handling.
For libraries and tests, use flags.Default &^ flags.PrintErrors
so callers control output.
Commands are struct fields tagged with command.
A command can own options, positional arguments, subcommands,
and an Execute(args []string) error method.
type AddCommand struct {
Name string `long:"name" required:"true"`
}
func (c *AddCommand) Execute(args []string) error {
fmt.Println("add", c.Name)
return nil
}
type Options struct {
Add AddCommand `command:"add" description:"Add item"`
}This gives a command shape like:
app add --name taskSmall tools often use tag defaults and environment variables:
type Options struct {
Port int `long:"port" default:"8080" env:"APP_PORT"`
Token string `long:"token" env:"APP_TOKEN" required:"true" secret:"true"`
}Applications that load a config file before parsing CLI arguments
can use flags.ConfiguredValues so prefilled struct values are kept
and can satisfy required checks.
INI and JSON config files are supported.
Automatic .env loading is available via the DotEnv parser option.
// .env is loaded automatically when DotEnv is set
parser := flags.NewParser(&opts, flags.Default|flags.DotEnv)
// INI - generated example included via the built-in config command
ini := flags.NewIniParser(parser)
_ = ini.ParseFile("app.ini")
// JSON - key names follow the json struct tag or the long tag;
// ParseAsDefaults lets CLI flags override values from the file
jp := flags.NewJSONParser(parser)
jp.ParseAsDefaults = true
_ = jp.ParseFile("app.json")JSONParser.ParseMap also accepts any map[string]interface{},
so YAML or TOML can be decoded externally
and applied without adding dependencies to the core module.
The same parser model can render user-facing output:
parser.WriteHelp(os.Stdout)
_ = parser.WriteNamedCompletion(os.Stdout, flags.CompletionShellBash, "app")
_ = parser.WriteDoc(os.Stdout, flags.DocFormatMarkdown)Use the source documentation when working in the repository:
docs/.
Use the published site for rendered guides and navigation:
Documentation Site.
Use Go Reference for API documentation generated from Go symbols:
Go Reference.