pflag
A drop-in replacement for Go's flag package that adds POSIX/GNU-style double-dash flags and shorthand letters.
Repository Health
Technical Analysis
pflag is a drop-in replacement for Go’s standard library flag package, implementing POSIX/GNU-style command-line flag parsing. Where the standard flag package only understands single-dash flags, pflag adds double-dash long flags (--verbose), single-letter shorthand flags (-v), combinable boolean shorthands (-abc), and the -- argument terminator, matching the conventions Unix users expect from any serious CLI tool.
Because it mirrors the standard flag package’s API almost exactly, most codebases can switch by changing a single import alias (import flag "github.com/spf13/pflag"). It adds typed accessors (GetInt, GetString, etc.), flag deprecation and hiding, custom name-normalization functions, and structured error types with Unwrap support for use with Go’s errors.Is/errors.As. It has zero external dependencies and is the flag-parsing engine underneath Cobra, Kubernetes’ kubectl, Docker, Helm, and a large share of the Go CLI ecosystem.
What You Get
- Long (
--flag) and shorthand (-f) flag definitions via*Pvariants of every standard constructor (IntP,BoolVarP,VarP, etc.) - Combinable boolean shorthand flags on the command line (
-abcinstead of-a -b -c) - Typed value getters on a
FlagSet(GetInt,GetString,GetDuration, …) so callers don’t need to track pointers - Structured, typed errors (
NotExistError,ValueRequiredError,InvalidValueError,InvalidSyntaxError) that implementUnwrapfor use witherrors.Is/errors.As - Flag deprecation and hiding (
MarkDeprecated,MarkHidden,MarkShorthandDeprecated) for maintaining CLI backward compatibility - Custom flag-name normalization (
SetNormalizeFunc) for treating-,_, and.as equivalent, or aliasing renamed flags - Interop with Go’s native
flagpackage viaAddGoFlagSet, so third-party libraries that still register standard flags keep working
Common Use Cases
- Building a CLI tool with GNU-style flags - a Go program wants
--verbose/-vstyle flags instead offlagpackage’s single-dash-only syntax - Implementing subcommands - each subcommand gets its own independent
pflag.FlagSet, the same pattern Cobra builds subcommand parsing on top of - Migrating from Go’s flag package with minimal changes - swap the import alias to
flag "github.com/spf13/pflag"and existingflag.String()/flag.Parse()call sites keep compiling - Supporting deprecated or renamed flags without breaking scripts -
MarkDeprecatedandSetNormalizeFunclet a CLI evolve its flag names while still accepting the old ones - Bridging third-party flag registrations -
AddGoFlagSetpulls in flags declared with the standard library’sflagpackage (e.g. fromglog) into the samepflag.FlagSet
Under The Hood
Architecture
pflag centers on the FlagSet type (flag.go), which owns two maps keyed by flag name and shorthand plus an ordered slice for stable iteration, and every constructor (String, Int, BoolVarP, …) is a thin wrapper that allocates a typed Value implementation and registers it via FlagSet.VarP. Each primitive type (string, int, bool, duration, IP, slices of each, …) lives in its own file (string.go, int_slice.go, duration.go, ipnet.go, etc.) implementing the small Value interface (String(), Set(string) error, Type() string), so adding a new flag type is additive and doesn’t touch the parser core. Parsing itself walks os.Args-style slices token by token in parseArgs, dispatching to parseLongArg or parseShortArg depending on the leading dashes, and a package-level CommandLine FlagSet plus top-level functions (pflag.String(), pflag.Parse()) exist purely as convenience wrappers over an application-created FlagSet, matching the standard library’s ergonomics. This is a flat, single-responsibility layout: parsing, storage, and value types are cleanly separated, and nothing in the core loop depends on any one flag type.
Tech Stack
pflag is pure Go with zero runtime dependencies (go.mod declares only module github.com/spf13/pflag and go 1.12, no require block), which is deliberate for a library this deep in the Go CLI ecosystem’s dependency graph. It targets the standard library exclusively (fmt, strconv, errors, os, net, time) and its own golangflag.go shim provides one-way interop with the standard flag package rather than depending on it as a library. CI (.github/workflows/ci.yaml) runs the test suite against a matrix from Go 1.12 through current stable plus “oldstable”, reflecting a deliberate promise of long backward compatibility for a foundational dependency.
Code Quality
The repository carries roughly one test file per feature file (32 _test.go files against a similar count of implementation files), covering both individual value types (bool_test.go, ip_test.go, duration_slice_test.go) and end-to-end flag-parsing behavior (flag_test.go, printusage_test.go). CI runs tests with -race, and errors are represented as concrete exported types (NotExistError, ValueRequiredError, InvalidValueError, InvalidSyntaxError in errors.go) that implement the error interface and, where they wrap an underlying cause, Unwrap() error — enabling callers to use errors.As instead of string-matching error messages. Naming is consistent with the standard library’s flag package throughout (XxxVarP for pointer-binding shorthand variants, GetXxx for typed lookups), which lowers the cost of reading the source for anyone already familiar with flag.
What Makes It Unique
pflag’s specific niche is being the POSIX/GNU-flag layer that a large share of the Go CLI ecosystem (Cobra, and transitively kubectl, Helm, Docker CLI, and many others) is built on, while staying a near drop-in replacement for the standard library rather than a from-scratch flag-parsing API. Its typed-error refactor (NotExistError/ValueRequiredError/etc. with Unwrap support) is a comparatively recent addition that lets consuming tools programmatically distinguish failure modes instead of parsing human-readable strings, without changing the error text those tools already print to users.
Used by 32 apps in this directory
agentgateway
AI Development · Developer Tools
An open source AI-native proxy that secures, observes, and governs agent-to-LLM, agent-to-tool, and agent-to-agent communication through MCP, A2A, and unified LLM routing.
Apache Airflow
Data Engineering
Define, schedule, and monitor complex data workflows as Python code — with a powerful UI, 80+ provider integrations, and battle-tested scalability across thousands of production deployments.
Argo Workflows
Devops · Data Engineering
The most popular Kubernetes-native workflow engine for orchestrating containerized DAGs, ML pipelines, CI/CD, and parallel batch jobs at scale.
Authelia
Security · Authentication
OpenID Certified SSO and MFA portal for securing self-hosted web applications behind reverse proxies.
Authgear
Authentication
Open-source, self-hostable authentication platform with passkeys, biometric login, SSO, MFA, and GraphQL admin API — a full Auth0/Clerk/Firebase alternative for SaaS and mobile apps.
Caddy
Devops · Security
The only web server that obtains and renews TLS certificates automatically, with HTTP/1-2-3 support and zero dependency on external runtimes.
Coder
Devops · Developer Tools · Code Editors
Self-hosted cloud development environments and AI coding agents — defined in Terraform, connected via WireGuard, automatically shut down when idle.
Cog
AI Development · Devops · Developer Tools
An open-source CLI that packages machine learning models into standard, production-ready Docker containers — no Dockerfile wrangling, no CUDA version hell.
Convoy
Developer Tools · Devops
Convoy is an open-source, cloud-native webhooks gateway that ingests events over HTTP or straight from Kafka, SQS, Google Pub/Sub, and RabbitMQ, then reliably delivers them to subscriber endpoints with signed payloads, automatic retries, circuit breaking, and JavaScript-based transformations.