Frontend Labs
⋯

Part IV — Real-world builds: terminal

Theory and internals are done — Parts I–III gave you everything the next three parts use. This one and the two after it are capstones: full, opinionated builds rather than isolated examples. This one stays on the terminal: a production-grade CLI, then two larger capstones (a job queue, a multi-GB log analyzer) that combine concurrency, I/O, and error handling into something closer to what you'd actually ship.

40. Building production CLIs: flag, subcommands, config precedence

40.1 The standard library's flag package

var (
	verbose = flag.Bool("verbose", false, "enable verbose logging")
	port    = flag.Int("port", 8080, "port to listen on")
	config  = flag.String("config", "", "path to config file")
)

func main() {
	flag.Parse()
	args := flag.Args() // positional args after all flags
}

40.2 Subcommands without a framework

flag.NewFlagSet gives each subcommand its own independent flag scope — this is literally how cobra-style CLIs (git commit -m, docker run -it) are built underneath, and it's often enough on its own for an internal tool:

func main() {
	if len(os.Args) < 2 {
		fmt.Println("usage: toolbelt <serve|migrate|version>")
		os.Exit(1)
	}
	switch os.Args[1] {
	case "serve":
		serveCmd := flag.NewFlagSet("serve", flag.ExitOnError)
		port := serveCmd.Int("port", 8080, "port")
		serveCmd.Parse(os.Args[2:])
		runServe(*port)
	case "migrate":
		migrateCmd := flag.NewFlagSet("migrate", flag.ExitOnError)
		dryRun := migrateCmd.Bool("dry-run", false, "preview only")
		migrateCmd.Parse(os.Args[2:])
		runMigrate(*dryRun)
	case "version":
		fmt.Println("toolbelt v1.0.0")
	default:
		fmt.Printf("unknown command %q\n", os.Args[1])
		os.Exit(1)
	}
}

For richer needs — nested subcommands, auto-generated help, shell completion — reach for github.com/spf13/cobra, which is flag.FlagSet composed at scale, not a different paradigm.

40.3 Config precedence: flags > env > file > defaults

The convention nearly every well-built CLI follows, highest priority first:

func resolvePort(flagVal *int, flagSet bool) int {
	if flagSet {
		return *flagVal // 1. explicit flag wins
	}
	if v := os.Getenv("APP_PORT"); v != "" { // 2. environment variable
		if p, err := strconv.Atoi(v); err == nil {
			return p
		}
	}
	if cfg.Port != 0 { // 3. config file value
		return cfg.Port
	}
	return 8080 // 4. hardcoded default
}

40.4 Exit codes and stderr vs. stdout

Reserve stdout for a program's actual output (so it composes with | and scripting); send diagnostics, warnings, and errors to stderr; and return a non-zero exit code (os.Exit(1)) on failure so shell scripts and CI can detect it:

if err := run(); err != nil {
	fmt.Fprintln(os.Stderr, "error:", err)
	os.Exit(1)
}

Generated from real-life-golang-guide.md · 8 Oct 2026 16:36