Skip to content

Cobra

Developer UtilitiesCLI/UtilsGo

What it is

Cobra is the CLI framework behind kubectl, Hugo, GitHub CLI and Docker, providing nested subcommands, flag parsing, help generation and shell completion.

Commands are structs arranged in a tree. Cobra handles argument parsing, help text, usage errors, and generates completion scripts for bash, zsh, fish and PowerShell.

Installation

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

Getting started

The smallest useful thing you can do with it, and what each part means.

Root command with a subcommand
var rootCmd = &cobra.Command{
    Use:   "library",
    Short: "Manage a book library",
}

var addCmd = &cobra.Command{
    Use:   "add [title]",
    Short: "Add a book",
    Args:  cobra.ExactArgs(1),
    RunE: func(cmd *cobra.Command, args []string) error {
        year, _ := cmd.Flags().GetInt("year")
        return store.Add(args[0], year)
    },
}

func init() {
    addCmd.Flags().IntP("year", "y", 0, "publication year")
    rootCmd.AddCommand(addCmd)
}
Use RunE rather than Run so errors propagate and Cobra prints them and sets a non-zero exit code. Args validators such as ExactArgs reject bad input before your code runs.
Persistent flags and context
rootCmd.PersistentFlags().Bool("verbose", false, "verbose output")

func main() {
    ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
    defer cancel()

    if err := rootCmd.ExecuteContext(ctx); err != nil {
        os.Exit(1) // Cobra already printed the error
    }
}
Persistent flags apply to a command and everything beneath it. ExecuteContext plus signal.NotifyContext means Ctrl-C cancels in-flight work cleanly.

Advanced usage

Where the library earns its place over a simpler alternative.

Shell completion for dynamic values
var getCmd = &cobra.Command{
    Use: "get [name]",
    ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
        if len(args) != 0 {
            return nil, cobra.ShellCompDirectiveNoFileComp
        }
        return store.NamesWithPrefix(toComplete), cobra.ShellCompDirectiveNoFileComp
    },
    RunE: run,
}
This is how kubectl completes pod names. Cobra generates the completion script; your function supplies the candidates at runtime.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

The error is printed twice
Cobra prints errors returned from RunE. Set SilenceErrors or SilenceUsage on the root command if you also print them yourself.
Flag values are empty inside Run
Flags registered on a child are not visible on the parent. Use PersistentFlags for shared options, and read them via cmd.Flags() rather than a package-level variable bound too early.

Best practices

  • Use RunE instead of Run so failures set a non-zero exit code.
  • Validate arguments with the built-in Args validators rather than checking len(args) by hand.
  • Print user-facing output with cmd.OutOrStdout() so tests can capture it.
  • Pair with Viper when you need flags, environment variables and a config file to layer together.

Background

Why it exists, and what it was reacting to.

Written by Steve Francia, Cobra became the de facto standard for Go command-line tools. Its command tree model is why so many Go CLIs share the same 'verb noun --flag' feel.