Building CLI Applications in Go

Learn how to build command-line interface (CLI) applications in Go using built-in and external libraries

Quick recipes for building CLI applications in Go using different approaches.

Basic CLI with Flag Package

package main

import (
	"flag"
	"fmt"
)

func main() {
	task := flag.String("task", "", "Task description.")	
	priority := flag.Int("priority", 1, "Priority (1-5).")
	flag.Parse()

	if *task == "" {
		fmt.Println("Error: Task required.")
		return
	}

	fmt.Printf("Added task: %s (Priority: %d)\n", *task, *priority)
}

Run with:

go run task.go -task="Complete project docs" -priority=3

Subcommands with Cobra

package main

import (
	"fmt"
	"github.com/spf13/cobra"
	"os"
)

func main() {
	var priority int

	rootCmd := &cobra.Command{
		Use:   "tasks",
		Short: "Task management CLI.",
	}

	addCmd := &cobra.Command{
		Use:   "add [task]",
		Short: "Add a new task.",
		Args:  cobra.ExactArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("Added task: %s (Priority: %d)\n", args[0], priority)
		},
	}

	addCmd.Flags().IntVarP(&priority, "priority", "p", 1, "Task priority (1-5)")
	rootCmd.AddCommand(addCmd)
	rootCmd.Execute()
}

Run with:

go run tasks.go add "Review code" -p 2

Quick CLI with Urfave/cli

package main

import (
	"fmt"
	"github.com/urfave/cli/v2"
	"os"
)

func main() {
	app := &cli.App{
		Name: "tasks",
		Commands: []*cli.Command{
			{
				Name:  "list",
				Usage: "List all tasks",
				Flags: []cli.Flag{
					&cli.BoolFlag{
						Name:    "completed",
						Aliases: []string{"c"},
						Usage:   "Show completed tasks",
					},
				},
				Action: func(c *cli.Context) error {
					if c.Bool("completed") {
						fmt.Println("Completed tasks:")
					} else {
						fmt.Println("Pending tasks:")
					}
					return nil
				},
			},
		},
	}

	app.Run(os.Args)
}

Run with:

go run tasks.go list --completed

Best Practices

  • Consider user-friendly error messages and application usage information.
  • Keep commands modular and use subcommands for better organization.
  • Make use of external libraries when advanced features are necessary, but keep dependencies minimal.
  • Use Go's flag package for simple applications and third-party libraries like Cobra or urfave/cli for complex needs.

Common Pitfalls

  • Not validating user inputs properly, leading to potential runtime errors.
  • Ignoring return values or errors, which might cause unhandled exceptions when the application runs.
  • Poor command organization leading to a confusing and non-intuitive CLI.

Performance Tips

  • Avoid unnecessary computations in Run or equivalent methods to keep the CLI responsive.
  • Cache repeated data fetches or computations when possible.
  • Profile and optimize the initialization time of your CLI application if start-up performance is an issue.

These strategies and examples demonstrate how Go can be leveraged effectively to create powerful and efficient command-line tools.