Golang Flag Examples (CLI Flags, Multiple Values, Subcommands)

Golang Flag Examples (CLI Flags, Multiple Values, Subcommands)

The Golang flag package is the standard way to handle command-line arguments in Go applications. It allows developers to define flags, set default values, and control program behavior dynamically based on user input, making it essential for building CLI tools and automation scripts.

In this guide, you will learn everything from basic flag usage to advanced techniques like handling multiple values, required flags, and subcommands. With practical examples and real-world scenarios, this tutorial will help you master Go command-line flags and build production-ready CLI applications.


Golang Flag Quick Cheat Sheet (Most Used Patterns)

Command / Code ExampleDescription
name := flag.String("name", "guest", "username")Define a string flag with default value
port := flag.Int("port", 8080, "port number")Define an integer flag
debug := flag.Bool("debug", false, "enable debug")Define a boolean flag
flag.Parse()Parse command-line inputs
fmt.Println(*name)Dereference pointer to get value
flag.StringVar(&name, "name", "guest", "username")Bind flag to existing variable
flag.Args()Retrieve non-flag arguments
flag.Arg(0)Get positional argument
flag.NArg()Count non-flag arguments
flag.Usage()Print usage message
flag.Usage = func() {}Customize help output
if name == "" { os.Exit(1) }Validate required flags manually
flag.Var(&list, "item", "add items")Custom flag for multiple inputs
flag.NewFlagSet("cmd", flag.ExitOnError)Create CLI subcommands
go run main.go -name=JohnPass flags via CLI
-debugSets boolean flag to true
-port=8080 -debug=trueUse multiple flags together

Basic Golang Flag Usage

Simple string, int and bool flag examples

Understand how to define basic flag types like string, integer, and boolean in Go CLI applications.

go
package main

import (
    "flag"
    "fmt"
)

func main() {
    name := flag.String("name", "guest", "username")
    port := flag.Int("port", 8080, "port number")
    debug := flag.Bool("debug", false, "enable debug")

    flag.Parse()

    fmt.Println("Name:", *name)
    fmt.Println("Port:", *port)
    fmt.Println("Debug:", *debug)
}

Run Go program with flags (go run flags)

Learn how to pass command-line flags while running Go programs using go run.

bash
go run main.go -name=John -port=9090 -debug=true

Default values and usage messages

Understand how default values work and how to display usage information for CLI users.

go
package main

import (
    "flag"
)

func main() {
    name := flag.String("name", "guest", "username")

    flag.Parse()

    flag.Usage()
}

Multiple Flags and Real CLI Examples

Use multiple flags together in a program

Combine multiple flags to control different aspects of application behavior.

go
package main

import (
    "flag"
    "fmt"
)

func main() {
    host := flag.String("host", "localhost", "server host")
    port := flag.Int("port", 8080, "server port")
    debug := flag.Bool("debug", false, "enable debug")

    flag.Parse()

    fmt.Printf("Connecting to %s:%d (debug=%v)\n", *host, *port, *debug)
}

Build a real CLI tool with flags

Example of a simple CLI tool using flags for configuration.

go
package main

import (
    "flag"
    "fmt"
)

func main() {
    filename := flag.String("file", "data.txt", "input file")
    mode := flag.String("mode", "read", "operation mode")

    flag.Parse()

    fmt.Println("File:", *filename)
    fmt.Println("Mode:", *mode)
}

Combine flags with positional arguments

Use flags along with positional arguments for flexible CLI input handling.

go
package main

import (
    "flag"
    "fmt"
)

func main() {
    user := flag.String("user", "guest", "username")

    flag.Parse()

    args := flag.Args()

    fmt.Println("User:", *user)
    fmt.Println("Arguments:", args)
}

Handling Required Flags in Golang

How to make flags mandatory (manual validation)

Golang does not support required flags directly, so validation must be done manually.

go
package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    name := flag.String("name", "", "username (required)")

    flag.Parse()

    if *name == "" {
        fmt.Println("Error: -name flag is required")
        os.Exit(1)
    }

    fmt.Println("Name:", *name)
}

Show custom error if flag is missing

Display user-friendly error messages and usage instructions when required flags are not provided.

go
package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    name := flag.String("name", "", "username")

    flag.Usage = func() {
        fmt.Println("Usage:")
        fmt.Println("  -name string (required)")
    }

    flag.Parse()

    if *name == "" {
        flag.Usage()
        os.Exit(1)
    }

    fmt.Println("Name:", *name)
}

Best practice for required flags

Combine validation and clear usage messages to improve CLI usability and avoid runtime errors.

go
if *name == "" {
    fmt.Println("Missing required flag: -name")
    flag.Usage()
    os.Exit(1)
}

Working with Multiple Values (Array Flags)

Accept multiple values using custom flag types

Use custom flag types to accept multiple values by implementing the flag.Value interface.

go
package main

import (
    "flag"
    "fmt"
)

type StringSlice []string

func (s *StringSlice) String() string {
    return fmt.Sprint(*s)
}

func (s *StringSlice) Set(value string) error {
    *s = append(*s, value)
    return nil
}

func main() {
    var items StringSlice

    flag.Var(&items, "item", "add multiple items")
    flag.Parse()

    fmt.Println("Items:", items)
}

Run:

bash
go run main.go -item apple -item banana -item mango

golang flag array example

Example of collecting multiple inputs into an array-like structure.

go
// Output:
Items: [apple banana mango]

Repeat flags vs comma-separated values

Understand two common approaches for passing multiple values via flags.

bash
# Repeat flag (recommended)
go run main.go -item apple -item banana

# Comma-separated (manual parsing required)
go run main.go -item apple,banana

Golang Flag Subcommands (Advanced CLI Design)

Create subcommands using flag.NewFlagSet

Use flag.NewFlagSet to define independent flag sets for each subcommand.

go
package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    addCmd := flag.NewFlagSet("add", flag.ExitOnError)
    value := addCmd.Int("value", 0, "value to add")

    if len(os.Args) < 2 {
        fmt.Println("expected 'add' subcommand")
        os.Exit(1)
    }

    switch os.Args[1] {
    case "add":
        addCmd.Parse(os.Args[2:])
        fmt.Println("Added:", *value)
    default:
        fmt.Println("unknown command")
    }
}

Example: git-like CLI using subcommands

Demonstrates how modern CLI tools structure commands and flags.

bash
go run main.go add -value=10

Parsing and Validating Flags

flag.Parse explained with examples

flag.Parse processes command-line inputs and assigns values to defined flags.

go
flag.Parse()

Validate flag inputs (range, format)

Validate inputs such as port range or string format after parsing.

go
if *port < 1 || *port > 65535 {
    fmt.Println("Invalid port number")
    os.Exit(1)
}

Handle invalid or unexpected inputs

Handle errors gracefully to improve CLI user experience.

go
if *name == "" {
    fmt.Println("Name cannot be empty")
    os.Exit(1)
}

Boolean and String Flags Deep Dive

golang flag bool behavior (true/false nuances)

Boolean flags default to false and become true when specified without a value.

bash
go run main.go -debug

Equivalent to:

bash
go run main.go -debug=true

flag.String vs StringVar difference

Understand the difference between pointer-based and variable-based flag definitions.

go
// Pointer-based
name := flag.String("name", "guest", "username")

// Variable-based
var username string
flag.StringVar(&username, "name", "guest", "username")

Common mistakes with string flags

Avoid common errors like forgetting to parse flags or not dereferencing pointer values.

go
flag.Parse()

fmt.Println(*name) // correct
// fmt.Println(name) // incorrect (prints pointer)

Using Flags with Environment Variables

Override flags using environment variables

Override flag values using environment variables to allow dynamic configuration without modifying code.

go
package main

import (
    "flag"
    "fmt"
    "os"
)

func main() {
    env := flag.String("env", "dev", "environment")

    flag.Parse()

    if val := os.Getenv("APP_ENV"); val != "" {
        *env = val
    }

    fmt.Println("Environment:", *env)
}

Run:

bash
APP_ENV=prod go run main.go

Config fallback pattern (env → flag → default)

Implement a layered configuration approach where environment variables override flags, and flags override default values.

go
env := flag.String("env", "dev", "environment")
flag.Parse()

if *env == "dev" {
    if val := os.Getenv("APP_ENV"); val != "" {
        *env = val
    }
}

Real-world DevOps use case

Use flags and environment variables together in automation scripts, containers, and CI/CD pipelines.

bash
APP_ENV=staging go run main.go -env=dev

Output:

text
Environment: staging

Error Handling and Custom Usage Output

Customize flag usage message

Override the default usage output to provide clearer instructions to users.

go
flag.Usage = func() {
    fmt.Println("Usage of application:")
    fmt.Println("  -name string (required)")
}

Control error handling behavior

Use different error handling modes like ExitOnError or ContinueOnError for better control.

go
cmd := flag.NewFlagSet("app", flag.ExitOnError)

Improve CLI UX with help messages

Provide meaningful help messages to guide users and reduce errors.

go
flag.Usage = func() {
    fmt.Println("Example:")
    fmt.Println("  go run main.go -name=John")
}

Summary

This guide covered everything you need to know about the Golang flag package, from basic usage to advanced CLI patterns like multiple values, subcommands, environment variable integration, and error handling. By applying these techniques, you can build flexible, user-friendly, and production-ready command-line applications in Go.


Official Documentation

For more details and advanced usage, refer to the official Golang documentation:

Golang flag package documentation

Antony Shikubu

Antony Shikubu

Systems Integration Engineer

Highly skilled software developer with expertise in Python, Golang, and AWS cloud services.