Go by Example

Command-Line Flags

The flag package parses named flags (--name=value or --name value), generates help text automatically, and provides typed accessors for string, int, bool, and duration values.

The flag package parses named command-line flags. Declare flags before calling flag.Parse(), then access their values through the returned pointers or with flag.Args() for remaining positional arguments.

Declare typed flags with flag.String, flag.Int, flag.Bool, and flag.Duration. Each returns a pointer to the flag's value. Call flag.Parse() to process os.Args[1:] before reading any flag value.

package main
 
import (
    "flag"
    "fmt"
)
 
func main() {
    host := flag.String("host", "localhost", "server hostname")
    port := flag.Int("port", 8080, "server port")
    verbose := flag.Bool("verbose", false, "enable verbose output")
 
    flag.Parse()
 
    fmt.Printf("host: %s\n", *host)
    fmt.Printf("port: %d\n", *port)
    fmt.Printf("verbose: %v\n", *verbose)
}

After flag.Parse(), flag.Args() returns the remaining non-flag positional arguments. This lets a command accept both flags and positional arguments in any order.

package main
 
import (
    "flag"
    "fmt"
)
 
func main() {
    output := flag.String("output", "stdout", "output destination")
    flag.Parse()
 
    positional := flag.Args()
    fmt.Printf("output: %s\n", *output)
    fmt.Printf("files:  %v\n", positional)
}
// Usage: ./tool --output=file.txt a.go b.go
// output: file.txt
// files:  [a.go b.go]

Override flag.Usage to customize the help message shown for -help or -h. The default usage lists all flags alphabetically with their defaults and descriptions.

package main
 
import (
    "flag"
    "fmt"
    "os"
)
 
func main() {
    timeout := flag.Duration("timeout", 0, "request timeout (0 = no timeout)")
 
    flag.Usage = func() {
        fmt.Fprintf(os.Stderr, "Usage: fetch [flags] <url>\n\nFlags:\n")
        flag.PrintDefaults()
    }
 
    flag.Parse()
 
    if flag.NArg() == 0 {
        flag.Usage()
        os.Exit(1)
    }
 
    fmt.Printf("fetching %s (timeout: %v)\n", flag.Arg(0), *timeout)
}

In production

The flag package is sufficient for single-command tools. Always set meaningful defaults and usage strings - they appear in the auto-generated -help output and are the primary documentation for most CLI tools. Always call flag.Parse() before reading any flag value; accessing a flag value before flag.Parse() returns the declared default, not the user-supplied value, which masks bugs silently. The flag package accepts both one- and two-dash forms: -name value, -name=value, --name value, and --name=value are all equivalent. What it does not support is combined short flags (-abc meaning -a -b -c) or positional-only GNU-style -- termination; for those patterns use a third-party library like pflag or cobra. For integration tests of CLI tools, flag.CommandLine can be reset between calls, but it is generally cleaner to refactor the tool so the flag set is a parameter rather than global state.

Enjoyed this? Get more essays on software craft delivered to your inbox.

Subscribe free