CLI frameworks for Go: Cobra, Urfave/cli, and Bubble Tea

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

CLI frameworks for Go: from simple utilities to TUI interfaces



Go (Golang) has become the #1 language for creating console utilities and DevOps tools. Thanks to fast compilation, built-in concurrency support, and simple distribution (a single binary file), Go is ideal for CLI. However, writing an argument parser, error handling, and colored output from scratch is a labor-intensive task. CLI frameworks come to the rescue. In this article, we will cover three key tools: Cobra, urfave/cli, and Bubble Tea.



1. Cobra — the industry standard



Cobra (github.com/spf13/cobra) is the most popular framework for Go. It is used by Kubernetes, Hugo, Docker, GitHub CLI. Cobra provides a powerful command generator, nested subcommands, autocompletion for bash/zsh/fish, and integration with Viper (configuration management).



Installation

go get -u github.com/spf13/cobra/cobra


Example: a simple application with subcommands

package main

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

func main() { var rootCmd = &cobra.Command{ Use: "app", Short: "Example application on Cobra", Run: func(cmd *cobra.Command, args []string) { fmt.Println("Root handler launched") }, }

var helloCmd = &cobra.Command{ Use: "hello [name]", Short: "Greet the user", Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { fmt.Printf("Hello, %s!", args[0]) }, }

rootCmd.AddCommand(helloCmd) rootCmd.Execute()}


Key features:

  • Automatic help generation (--help)
  • Support for flags (persistent, local)
  • Argument validation
  • Generation of autocompletion scripts
  • Integration with Viper for configuration


2. Urfave/cli — simplicity and flexibility



Urfave/cli (github.com/urfave/cli/v2) is a lightweight alternative to Cobra. The framework is declarative: you describe commands, flags, and actions in structures. Ideal for small and medium-sized utilities.



Installation

go get github.com/urfave/cli/v2


Example: a file utility

package main

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

func main() { app := &cli.App{ Name: "fileutil", Usage: "utility for working with files", Commands: []*cli.Command{ { Name: "read", Aliases: []string{"r"}, Usage: "read a file", Action: func(cCtx *cli.Context) error { if cCtx.NArg() == 0 { return fmt.Errorf("specify the file name") } data, _ := os.ReadFile(cCtx.Args().First()) fmt.Println(string(data)) return nil }, }, { Name: "write", Aliases: []string{"w"}, Usage: "write a string to a file", Flags: []cli.Flag{ &cli.StringFlag{ Name: "content", Aliases: []string{"c"}, Usage: "content to write", }, }, Action: func(cCtx *cli.Context) error { content := cCtx.String("content") if content == "" { return fmt.Errorf("specify --content") } return os.WriteFile(cCtx.Args().First(), []byte(content), 0644) }, }, }, }

if err := app.R

Recommendations