Go by Example

Command-Line Subcommands

flag.NewFlagSet creates a per-subcommand flag set, enabling tools with subcommands like "git commit" or "docker run" where each subcommand has its own flags.

flag.NewFlagSet creates an independent parser for a command. Read the first argument to choose a command, then parse the remaining arguments with its flag set.

Each subcommand can define flags with its own names and defaults. Check that a command was supplied before accessing os.Args[1].

package main
 
import (
    "flag"
    "fmt"
    "os"
)
 
func main() {
    build := flag.NewFlagSet("build", flag.ExitOnError)
    output := build.String("output", "app", "binary name")
 
    if len(os.Args) < 2 {
        fmt.Fprintln(os.Stderr, "usage: tool build [flags]")
        os.Exit(1)
    }
    if os.Args[1] != "build" {
        fmt.Fprintln(os.Stderr, "unknown command:", os.Args[1])
        os.Exit(1)
    }
    build.Parse(os.Args[2:])
    fmt.Println("building", *output, "with args", build.Args())
}

In production

FlagSet is enough for a small CLI. Keep command behavior in functions that accept an argument slice and return an error; this makes commands easier to test without changing process-wide os.Args.

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