fmt, io, os, bufio, encoding/json, net/http, time, slog, regexp, flag, embed.
flag — Command-Line Arguments
Go ships a tiny flag parser in the standard library. It's enough for most CLIs
and devops tools; reach for spf13/cobra only when you need subcommands and
shell completion.
Defining flags
- The return is a pointer —
*port,*name,*verbose. - Defaults are baked in:
flag.Int(name, default, usage). flag.Parse()walksos.Args[1:]once. Call it once, at the top ofmain.
Both syntaxes are accepted
Go's flag package accepts -port=80, -port 80, and --port=80 — the
double-dash is just sugar. Mix-and-match works, which is friendlier than
Unix-getopt strictness.
Var-style: bind to your own variable
If you want a typed config struct instead of a pile of pointers:
type Config struct {
Port int
Name string
Verbose bool
}
var cfg Config
flag.IntVar(&cfg.Port, "port", 8080, "TCP port")
flag.StringVar(&cfg.Name, "name", "world", "who to greet")
flag.BoolVar(&cfg.Verbose, "v", false, "verbose")
flag.Parse()
Same behaviour, no pointer dereferencing at the callsite.
Custom types via flag.Value
Any type implementing String() string and Set(string) error can be a flag.
A common case: comma-separated lists.
type stringList []string
func (s *stringList) String() string { return strings.Join(*s, ",") }
func (s *stringList) Set(v string) error { *s = strings.Split(v, ","); return nil }
var tags stringList
flag.Var(&tags, "tags", "comma-separated tags")
Now -tags=a,b,c populates tags.
Help text & usage
-h / -help is wired up automatically. The output uses the usage strings you
passed to flag.Int/String/etc. To customise the header:
flag.Usage = func() {
fmt.Fprintln(os.Stderr, "myapp: a small example")
flag.PrintDefaults()
}
Subcommands?
flag doesn't have first-class subcommands, but flag.NewFlagSet lets you
build them by hand:
serve := flag.NewFlagSet("serve", flag.ExitOnError)
port := serve.Int("port", 8080, "")
serve.Parse(os.Args[2:])
Beyond two or three subcommands, switching to spf13/cobra
is usually worth it.