Learn Go← Dashboard

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

go playground
Loading...
  • The return is a pointer*port, *name, *verbose.
  • Defaults are baked in: flag.Int(name, default, usage).
  • flag.Parse() walks os.Args[1:] once. Call it once, at the top of main.

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.

`myapp foo.txt -v` doesn't see `-v` as a flag. Why?