flag

Guided tour · CLI & Runtime · pkg.go.dev →

Command-line flag parsing. Built in, zero-dependency, handles the 90% case.

Basic flags

String, Int, Bool

Each returns a pointer. After flag.Parse(), dereference to read the value.

var (
    addr    = flag.String("addr", ":8080", "listen address")
    timeout = flag.Duration("timeout", 30*time.Second, "request timeout")
    debug   = flag.Bool("debug", false, "enable debug logging")
)

func main() {
    flag.Parse()
    fmt.Println(*addr, *timeout, *debug)
}

Var forms — bind to existing variables

var port int
flag.IntVar(&port, "port", 8080, "port to listen on")

Positional arguments

flag.Args and flag.Arg

Everything after the flags lives in flag.Args(). flag.NArg() is the count.

flag.Parse()
for i, a := range flag.Args() {
    fmt.Printf("positional %d: %s\n", i, a)
}

Subcommands with FlagSet

One FlagSet per subcommand

flag has no native subcommand concept — use one FlagSet per command and dispatch on os.Args[1].

serve := flag.NewFlagSet("serve", flag.ExitOnError)
addr := serve.String("addr", ":8080", "")

migrate := flag.NewFlagSet("migrate", flag.ExitOnError)
target := migrate.String("to", "latest", "")

switch os.Args[1] {
case "serve":
    serve.Parse(os.Args[2:])
    runServe(*addr)
case "migrate":
    migrate.Parse(os.Args[2:])
    runMigrate(*target)
}

Custom Value types

flag.Value interface — repeatable -tag flags

type stringList []string
func (s *stringList) String() string     { return strings.Join(*s, ",") }
func (s *stringList) Set(v string) error { *s = append(*s, v); return nil }

var tags stringList
flag.Var(&tags, "tag", "repeatable")

// $ app -tag a -tag b -tag c