CLI Tools Best Practices
Testing CLIs, versioning, and distributing via go install.
Search across all documentation pages
Testing CLIs, versioning, and distributing via go install.
Apply these rules in code review, release pipelines, and internal platform templates so every Go binary installs predictably, fails clearly, and stays testable without global flag pollution.
kubectl wrappers stay clean.NO_COLOR and disable ANSI when not a TTY. CI logs and accessibility policies depend on it.main thin; put logic in internal/ packages. Enables unit tests without os.Exit.flag.CommandLine in libraries. Use FlagSet or cobra per command.internal/. CLI and API stay aligned on enums and IDs.API_URL to api.url predictably.config.example.yaml with placeholders.PersistentFlags on the root only. Avoid duplicate flag names on parent and child.Args helpers or enums. Wrong arg counts produce actionable messages.run(args []string) error without parsing real os.Args. Core logic stays parallel-safe.cobra.Command.SetArgs or isolated FlagSet.Parse in CLI tests. No cross-test flag bleed.os/exec integration tests for exit codes and help output. Catch wiring mistakes in main.--help when command surface is stable. Unintended flag renames break scripts.go test ./... with race detector for concurrent CLIs. Workers and TUIs expose races early.-ldflags "-X main.version=…" in CI. Support can map bug reports to builds.--version or version subcommand. Matches container image tags and git tags.go install module/path@version for public modules. Document the import path in README.go.sum integrity and reproducible build notes in releases. Supply-chain review depends on it.ctrl+c and signals for batch CLIs. Partial writes should not corrupt remote state.Stdout/stderr separation, documented exit codes, thin main, config validation, and at least one CLI integration test are strong CI blockers.
Document exceptions in the tool README.
Yes.
cobra handles parsing; streams, testing, versioning, and distribution rules still apply.
Basics teaches flag and subcommand mechanics.
This list encodes production habits for teams shipping CLIs to operators and CI.
When subcommands are manual, flags are few, and help text is hand-maintained.
Re-evaluate when completion or persistent flags become todo items every sprint.
Even internal tools benefit from Linux CI binaries.
macOS developers still need native builds or go install from module tags.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 18, 2026