Jesse A. Green / notebook

Cobra User Guide

Generated June 2026 from spf13/cobra at ad460ea

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Cobra is a library for building modern command-line interface (CLI) applications in Go. It powers the command structure behind tools such as kubectl, hugo, the GitHub CLI (gh), and the go toolchain's cousins. If you are writing a Go program that needs subcommands, flags, automatic help text, shell completions, and generated documentation, Cobra gives you all of it from a small amount of declarative code.

This guide is written for the developer who consumes Cobra — you import it into your Go program and use its API. It shows you how to install Cobra, define commands, wire up flags and arguments, control the execution lifecycle, and ship polished extras like shell completion and man pages. Every command, field, function, and environment variable described here comes directly from the Cobra source.

Note

Cobra is a library, not a standalone program. You do not "run Cobra" — you build a Go binary that imports Cobra. Throughout this guide, "your program" or "your CLI" means the application you are building, and app is used as a placeholder for its name.


Table of Contents

  1. Quick Start
  2. Installation & Requirements
  3. Core Concepts
  4. Defining Commands
  5. Working with Flags
  6. Validating Positional Arguments
  7. The Run Lifecycle (Hooks)
  8. Organizing Commands
  9. Shell Completions
  10. Active Help
  11. Generating Documentation
  12. Versioning, Help, and Error Output
  13. Global Behavior Toggles
  14. Common Recipes
  15. Troubleshooting
  16. FAQ
  17. Quick Reference

1. Quick Start

A minimal Cobra program is a single root command that you execute from main.

package main

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
)

func main() {
	rootCmd := &cobra.Command{
		Use:   "hello",
		Short: "Hello prints a friendly greeting",
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Fprintln(cmd.OutOrStdout(), "Hello, world!")
		},
	}

	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}

Build and run it:

go run . 
Hello, world!

Ask for help — Cobra wires this up automatically:

go run . --help
Hello prints a friendly greeting

Usage:
  hello [flags]

Flags:
  -h, --help   help for hello

Tip

You never have to write a --help flag or a usage message yourself. Cobra adds the -h, --help flag to every command automatically the first time it executes (see InitDefaultHelpFlag).

That is the whole loop: build a *cobra.Command, give it a Run function, and call Execute(). Everything else in this guide is about adding structure — subcommands, flags, validation, and polish — on top of this foundation.


2. Installation & Requirements

Requirements

Requirement Detail
Go version Go 1.15 or newer (declared in Cobra's go.mod)
Module mode Go modules must be enabled (the default since Go 1.16)
Platforms Linux, macOS, Windows (a Windows-specific helper is built in — see mousetrap)

Cobra pulls in a small set of dependencies automatically when you go get it:

Dependency Role
github.com/spf13/pflag POSIX/GNU-style flag parsing. Cobra's flag API is a thin layer over pflag.
github.com/cpuguy83/go-md2man/v2 Renders man pages (used by the doc package).
github.com/inconshreveable/mousetrap Detects when a Windows program was launched from Explorer.
go.yaml.in/yaml/v3 Marshals YAML documentation (used by the doc package).

Add Cobra to your project

New project

mkdir myapp && cd myapp
go mod init github.com/you/myapp
go get github.com/spf13/cobra@latest

Existing module

go get github.com/spf13/cobra@latest

Then import it in your code:

import "github.com/spf13/cobra"

Note

Cobra ships a companion generator tool (cobra-cli) in a separate repository for scaffolding a command tree. It is optional — this guide builds everything by hand so you understand exactly what each piece does. Nothing in this guide requires the generator.

Verify the installation

go build ./...
# (no output on success)

A clean build with no cannot find package errors confirms Cobra and its dependencies resolved correctly.


3. Core Concepts

Cobra is built around three ideas. Understanding them makes the rest of the API obvious.

Command : A *cobra.Command represents a single action your program can perform — git commit, kubectl get, or your own app serve. Commands nest: a root command has children, which can have their own children. The first word of a command's Use field is its name.

Flag : A named option such as --verbose or -o json. Flags are parsed by pflag and attached to commands. A flag is either local (applies only to the command it is set on) or persistent (also applies to all descendant commands).

Argument : A positional value left over after flags are removed — e.g. the main.go in app build main.go. You can validate how many arguments a command accepts and which values are allowed.

A Cobra application is a tree of commands. Execution always starts at the root, walks the tree to find the command that matches the user's input, parses the flags, validates the arguments, and runs the matched command's Run function.

app                 (root command)
├── serve           (subcommand)
├── migrate         (subcommand)
│   ├── up          (sub-subcommand)
│   └── down        (sub-subcommand)
└── version         (subcommand)

Important

The first word of Use is the command's name. Use: "serve [flags]" produces a command named serve. Cobra derives the name with Command.Name(), which returns everything up to the first space.


4. Defining Commands

The Command struct

You configure a command by setting fields on a cobra.Command literal. These are the fields you will use most often:

Field Type Purpose
Use string One-line usage. First word is the command name.
Aliases []string Alternate names that invoke this command.
Short string One-line description shown in the parent's command list.
Long string Full description shown in this command's own help.
Example string Example invocations shown under an Examples: heading.
Run func(cmd *Command, args []string) The work function.
RunE func(cmd *Command, args []string) error Like Run but returns an error. Prefer this.
Args PositionalArgs Argument count/validity rule (see §6).
ValidArgs []Completion Allowed non-flag arguments, offered in completion.
Version string Enables a --version flag for this command.
Deprecated string Marks the command deprecated; the message prints when used.
Hidden bool Hides the command from help output (it still works).
GroupID string Groups this subcommand under a heading in the parent's help.
SuggestFor []string Names for which this command is suggested.
Annotations map[string]string Arbitrary key/value metadata for your own use.

Tip

Use RunE rather than Run in real applications. Returning an error lets Cobra print it consistently and lets Execute() signal failure to your main. Reserve Run for trivial commands that cannot fail.

Usage string syntax

The Use field documents the command's arguments. Cobra recommends this notation (taken from the field's own documentation):

Notation Meaning
[ ] An optional argument. Arguments not in brackets are required.
... You may specify multiple values for the previous argument.
| Mutually exclusive — use the left argument or the right, not both.
{ } A set of mutually exclusive arguments, one of which is required.
Use: "add [-F file | -D dir]... [-f format] profile"

Adding subcommands

Build child commands and attach them with AddCommand:

var rootCmd = &cobra.Command{Use: "app"}

var serveCmd = &cobra.Command{
	Use:   "serve",
	Short: "Start the HTTP server",
	RunE: func(cmd *cobra.Command, args []string) error {
		return startServer()
	},
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Fprintln(cmd.OutOrStdout(), "app v1.0.0")
	},
}

func init() {
	rootCmd.AddCommand(serveCmd, versionCmd)
}
app serve
app version

Note

AddCommand accepts one or more commands in a single call: rootCmd.AddCommand(serveCmd, versionCmd, migrateCmd). A command may not be added as a child of itself — Cobra panics with Command can't be a child of itself if you try.

Aliases and suggestions

var listCmd = &cobra.Command{
	Use:        "list",
	Aliases:    []string{"ls", "l"},
	SuggestFor: []string{"show"},
	Short:      "List all items",
	Run:        func(cmd *cobra.Command, args []string) { /* ... */ },
}
  • Aliases — app ls and app l both invoke list.
  • SuggestFor — if the user types app show, Cobra suggests list in its "Did you mean this?" message.

Cobra automatically suggests near-matches for mistyped commands using Levenshtein distance:

app serv
Error: unknown command "serv" for "app"

Did you mean this?
	serve

Run 'app --help' for usage.

The suggestion threshold is controlled by SuggestionsMinimumDistance (default 2). Set DisableSuggestions: true on a command to turn the feature off.


5. Working with Flags

Cobra exposes flags through pflag. You declare flags on a command's flag set inside init() (or before calling Execute).

Local vs. persistent flags

Method Scope
cmd.Flags() Local — applies only to this command.
cmd.PersistentFlags() Persistent — applies to this command and all of its children.
func init() {
	// Persistent: available on rootCmd and every subcommand
	rootCmd.PersistentFlags().BoolP("verbose", "v", false, "enable verbose logging")

	// Local: only valid on serveCmd
	serveCmd.Flags().IntP("port", "p", 8080, "port to listen on")
	serveCmd.Flags().StringP("host", "H", "localhost", "host to bind to")
}

The four arguments to a typed flag constructor are name, shorthand, default value, and usage string. The P suffix (BoolP, IntP, StringP, …) means "with a shorthand". Without the P, omit the shorthand:

serveCmd.Flags().Bool("tls", false, "enable TLS")   // long form only: --tls

Reading flag values

Inside a Run/RunE function, read flags from the command:

RunE: func(cmd *cobra.Command, args []string) error {
	port, _ := cmd.Flags().GetInt("port")
	verbose, _ := cmd.Flags().GetBool("verbose")  // works: persistent flag is inherited
	host, _ := cmd.Flags().GetString("host")
	fmt.Fprintf(cmd.OutOrStdout(), "serving on %s:%d (verbose=%t)\n", host, port, verbose)
	return nil
}

Alternatively, bind a flag to a variable with the *Var constructors:

var port int
serveCmd.Flags().IntVarP(&port, "port", "p", 8080, "port to listen on")
// `port` now holds the parsed value after flag parsing

Required flags

Mark a flag required so Cobra errors if it is missing:

serveCmd.Flags().String("config", "", "path to config file")
serveCmd.MarkFlagRequired("config")
Error: required flag(s) "config" not set

For a persistent flag, use MarkPersistentFlagRequired.

Flag groups

Express relationships between flags. Cobra validates them before running the command:

Method Rule enforced
cmd.MarkFlagsRequiredTogether("a", "b") If any of these flags is set, all must be set.
cmd.MarkFlagsOneRequired("a", "b") At least one of these flags must be set.
cmd.MarkFlagsMutuallyExclusive("a", "b") At most one of these flags may be set.
func init() {
	serveCmd.Flags().String("tls-cert", "", "TLS certificate file")
	serveCmd.Flags().String("tls-key", "", "TLS key file")
	serveCmd.MarkFlagsRequiredTogether("tls-cert", "tls-key")

	serveCmd.Flags().Bool("json", false, "JSON output")
	serveCmd.Flags().Bool("yaml", false, "YAML output")
	serveCmd.MarkFlagsMutuallyExclusive("json", "yaml")
}

The exact errors Cobra produces (from source):

if any flags in the group [tls-cert tls-key] are set they must all be set; missing [tls-key]
if any flags in the group [json yaml] are set none of the others can be; [json yaml] were all set
at least one of the flags in the group [a b] is required

Warning

The flags named in a group must already be defined on the command (or be persistent flags reachable from it) when you call the MarkFlags* method. If a named flag does not exist, Cobra panics — for example Failed to find flag "tls-key" and mark it as being required in a flag group. Define flags first, then group them.

Tying file/directory completion to a flag

These helpers tell shell completion how to complete a flag's value:

Method Effect
cmd.MarkFlagFilename("f", "json", "yaml") Complete only files ending in the given extensions.
cmd.MarkFlagDirname("d") Complete only directory names.
serveCmd.Flags().String("config", "", "config file")
serveCmd.MarkFlagFilename("config", "yaml", "yml", "json")

6. Validating Positional Arguments

Set a command's Args field to one of Cobra's built-in validators. They run after flag parsing and before Run.

Validator Passes when…
cobra.NoArgs No positional arguments are given.
cobra.ArbitraryArgs Always (any number of arguments).
cobra.MinimumNArgs(n) At least n arguments.
cobra.MaximumNArgs(n) At most n arguments.
cobra.ExactArgs(n) Exactly n arguments.
cobra.RangeArgs(min, max) Between min and max arguments (inclusive).
cobra.OnlyValidArgs Every argument is listed in the command's ValidArgs.
cobra.NoDuplicateArgs No argument value is repeated.
cobra.MatchAll(v1, v2, …) All of the supplied validators pass.
var deleteCmd = &cobra.Command{
	Use:  "delete [names...]",
	Args: cobra.MinimumNArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		for _, name := range args {
			// args holds the validated positional values
		}
		return nil
	},
}

The exact error messages each validator emits (from source):

Validator Error message format
MinimumNArgs(n) requires at least %d arg(s), only received %d
MaximumNArgs(n) accepts at most %d arg(s), received %d
ExactArgs(n) accepts %d arg(s), received %d
RangeArgs(min,max) accepts between %d and %d arg(s), received %d
NoArgs unknown command %q for %q
OnlyValidArgs invalid argument %q for %q
NoDuplicateArgs duplicate argument %q for %q

Combining validators with MatchAll

MatchAll runs several validators in sequence. Use it to require both a count and a value constraint:

var pickCmd = &cobra.Command{
	Use:       "pick",
	ValidArgs: []string{"red", "green", "blue"},
	Args:      cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
	Run:       func(cmd *cobra.Command, args []string) { /* ... */ },
}

Note

If you leave Args unset (nil), Cobra applies legacy behavior: a command with no subcommands accepts arbitrary arguments, while a root command with subcommands rejects unknown commands. Setting Args explicitly is recommended for predictable behavior.

Caution

cobra.ExactValidArgs(n) still exists but is deprecated. Use cobra.MatchAll(cobra.ExactArgs(n), cobra.OnlyValidArgs) instead — it is the exact replacement.


7. The Run Lifecycle (Hooks)

A command can define hook functions that run around its main Run. The order is fixed and documented in the Cobra source:

  1. PersistentPreRun / PersistentPreRunE
  2. PreRun / PreRunE
  3. Run / RunE
  4. PostRun / PostRunE
  5. PersistentPostRun / PersistentPostRunE

Every hook has a plain form and an E form that returns an error. If both are defined on a command, only the E form runs. All hooks receive the same arguments (the positional args after the command name).

var rootCmd = &cobra.Command{
	Use: "app",
	PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
		return loadConfig()          // runs before every subcommand
	},
}

var serveCmd = &cobra.Command{
	Use: "serve",
	PreRun:  func(cmd *cobra.Command, args []string) { openLogFile() },
	RunE:    func(cmd *cobra.Command, args []string) error { return serve() },
	PostRun: func(cmd *cobra.Command, args []string) { closeLogFile() },
}

Inheritance of persistent hooks

PersistentPreRun(E) and PersistentPostRun(E) are inherited by children — but with an important default: only the first one found while walking up the tree executes. If both the root and a subcommand define PersistentPreRunE, only the subcommand's runs.

Important

To run every persistent hook from the root down to the executed command (and every persistent post-run back up), set the package variable cobra.EnableTraverseRunHooks = true. With it off (the default), inner persistent hooks override outer ones rather than chaining.

Warning

PersistentPostRun(E) and PostRun(E) do not run if RunE (or PreRunE) returns an error — execution stops at the failing hook. This is a frequent source of confusion when using post-run hooks for cleanup; put unconditional cleanup in a defer inside RunE instead, or handle it explicitly.

Per-command initializers

For setup that should run on every command's Execute, register a function with OnInitialize; for teardown, use OnFinalize:

func init() {
	cobra.OnInitialize(initLogging)
	cobra.OnFinalize(flushLogging)
}

8. Organizing Commands

Grouping subcommands in help

When a command has many children, group them under headings. Define a group on the parent, then set each child's GroupID:

func init() {
	rootCmd.AddGroup(&cobra.Group{ID: "ops", Title: "Operations:"})
	rootCmd.AddGroup(&cobra.Group{ID: "info", Title: "Information:"})

	serveCmd.GroupID = "ops"
	migrateCmd.GroupID = "ops"
	versionCmd.GroupID = "info"

	rootCmd.AddCommand(serveCmd, migrateCmd, versionCmd)
}
Operations:
  migrate     Run database migrations
  serve       Start the HTTP server

Information:
  version     Print the version number

Caution

If you set a GroupID on a child but never register that group on the parent with AddGroup, Cobra panics at startup: group id 'ops' is not defined for subcommand 'app serve'. Always add the group before assigning its ID.

Additional help topics

A command with a Short/Long description but no Run function and no runnable children becomes an additional help topic — it appears under "Additional help topics" in help output and can be read with app help <topic> but cannot be executed.

Controlling output streams

Cobra commands write through accessor methods so you can redirect output (useful in tests):

Method Returns
cmd.OutOrStdout() The configured out writer, or os.Stdout.
cmd.ErrOrStderr() The configured err writer, or os.Stderr.
cmd.InOrStdin() The configured in reader, or os.Stdin.

Set them with cmd.SetOut(w), cmd.SetErr(w), and cmd.SetIn(r). There are also convenience print helpers that honor these streams: cmd.Print, cmd.Println, cmd.Printf, cmd.PrintErr, cmd.PrintErrln, cmd.PrintErrf.

Tip

Always write through cmd.OutOrStdout() instead of fmt.Println. It makes your command testable (you can capture output with cmd.SetOut(buf)) and lets a parent command redirect a child's output.


9. Shell Completions

This is one of Cobra's signature features. Any Cobra program automatically gains a completion command that emits a completion script for bash, zsh, fish, or PowerShell — you do not write any of it.

app completion --help
Generate the autocompletion script for app for the specified shell.
See each sub-command's help for details on how to use the generated script.

Usage:
  app completion [command]

Available Commands:
  bash        Generate the autocompletion script for bash
  fish        Generate the autocompletion script for fish
  powershell  Generate the autocompletion script for powershell
  zsh         Generate the autocompletion script for zsh

Enabling completion for your shell

The Long help of each subcommand contains exact, copy-pasteable instructions. The essentials:

bash

# current session
source <(app completion bash)

# every session (Linux)
app completion bash > /etc/bash_completion.d/app

# every session (macOS, Homebrew)
app completion bash > $(brew --prefix)/etc/bash_completion.d/app

zsh

# enable completion once, if not already enabled
echo "autoload -U compinit; compinit" >> ~/.zshrc

# current session
source <(app completion zsh)

# every session (Linux)
app completion zsh > "${fpath[1]}/_app"

# every session (macOS, Homebrew)
app completion zsh > $(brew --prefix)/share/zsh/site-functions/_app

fish

# current session
app completion fish | source

# every session
app completion fish > ~/.config/fish/completions/app.fish

powershell

# current session
app completion powershell | Out-String | Invoke-Expression

# every session: add the above line's output to your PowerShell profile

Note

The bash script depends on the bash-completion package. If completion does not work in bash, install bash-completion via your OS package manager and start a new shell.

Completing your command's arguments

Out of the box, completion suggests subcommand names, flag names, and required flags. To complete argument values, provide them via ValidArgs (static) or ValidArgsFunction (dynamic).

Static — a fixed list:

var setCmd = &cobra.Command{
	Use:       "set-level",
	ValidArgs: []string{"debug", "info", "warn", "error"},
	Args:      cobra.OnlyValidArgs,
	Run:       func(cmd *cobra.Command, args []string) { /* ... */ },
}

Dynamic — computed at completion time:

var openCmd = &cobra.Command{
	Use: "open",
	ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
		// e.g. list open projects matching `toComplete`
		return []cobra.Completion{"alpha", "beta"}, cobra.ShellCompDirectiveNoFileComp
	},
	Run: func(cmd *cobra.Command, args []string) { /* ... */ },
}

Add descriptions to completions with cobra.CompletionWithDesc("choice", "description") (zsh and fish display the description).

Completing flag values

Register a completion function for a specific flag with RegisterFlagCompletionFunc:

serveCmd.Flags().String("region", "", "deployment region")
serveCmd.RegisterFlagCompletionFunc("region",
	func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
		return []cobra.Completion{"us-east-1", "eu-west-1"}, cobra.ShellCompDirectiveNoFileComp
	})

Warning

RegisterFlagCompletionFunc returns an error if the flag does not exist (RegisterFlagCompletionFunc: flag '...' does not exist) or if you register the same flag twice (... already registered). Register completion only after the flag is defined, and only once per flag.

Completion directives

A completion function returns a ShellCompDirective bitmask that tells the shell how to behave. Combine them with |.

Directive Effect
ShellCompDirectiveDefault Let the shell do its default (file) completion. The zero value.
ShellCompDirectiveNoSpace Do not append a space after the completion.
ShellCompDirectiveNoFileComp Do not fall back to file completion.
ShellCompDirectiveFilterFileExt Treat the returned values as file-extension filters.
ShellCompDirectiveFilterDirs Complete directory names only.
ShellCompDirectiveKeepOrder Preserve the order you returned completions in (don't sort).
ShellCompDirectiveError Signal an error; completions are ignored.

Two ready-made completion functions cover common cases:

  • cobra.NoFileCompletions — disables file completion for a command/flag that takes no completable value.
  • cobra.FixedCompletions(choices, directive) — always returns the same list.
cmd.ValidArgsFunction = cobra.NoFileCompletions

Controlling the generated completion command

Customize or disable the built-in completion command via the root command's CompletionOptions:

Field Effect
DisableDefaultCmd Do not create the completion command at all.
DisableNoDescFlag Do not add the --no-descriptions flag.
DisableDescriptions Turn off completion descriptions entirely.
HiddenDefaultCmd Keep the completion command but hide it from help.
rootCmd.CompletionOptions.DisableDefaultCmd = true

10. Active Help

Active Help lets you push contextual messages to users during completion — for example, a hint when no completions are available. Build the messages onto your completion slice with AppendActiveHelp:

ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]cobra.Completion, cobra.ShellCompDirective) {
	var comps []cobra.Completion
	if len(args) == 0 {
		comps = cobra.AppendActiveHelp(comps, "You must specify a project name")
	}
	return comps, cobra.ShellCompDirectiveNoFileComp
},

Users (or you) can disable Active Help through environment variables, read at completion time:

Variable Effect
COBRA_ACTIVE_HELP=0 Globally disable Active Help for any Cobra program.
<PROGRAM>_ACTIVE_HELP=0 Disable Active Help for your program specifically. <PROGRAM> is your root command's name, upper-cased, with non-alphanumeric characters replaced by _.

Note

The <PROGRAM> prefix is derived from rootCmd.Name(). A program named my-app reads MY_APP_ACTIVE_HELP.


11. Generating Documentation

The github.com/spf13/cobra/doc subpackage turns your command tree into documentation files. It supports four formats, each with a single-file and a whole-tree generator.

Format Tree generator Single-command generator
Man pages doc.GenManTree(cmd, header, dir) doc.GenMan(cmd, header, w)
Markdown doc.GenMarkdownTree(cmd, dir) doc.GenMarkdown(cmd, w)
reStructuredText doc.GenReSTTree(cmd, dir) doc.GenReST(cmd, w)
YAML doc.GenYamlTree(cmd, dir) doc.GenYaml(cmd, w)

Generate a full Markdown tree:

package main

import (
	"log"

	"github.com/spf13/cobra/doc"
)

func main() {
	if err := doc.GenMarkdownTree(rootCmd, "./docs"); err != nil {
		log.Fatal(err)
	}
}

Generate man pages with a header:

header := &doc.GenManHeader{
	Title:   "APP",
	Section: "1",
	Source:  "App 1.0",
}
if err := doc.GenManTree(rootCmd, header, "./man"); err != nil {
	log.Fatal(err)
}

Each generator has a *Custom variant (GenMarkdownTreeCustom, GenManTreeFromOpts, GenReSTTreeCustom, GenYamlTreeCustom) that accepts a filePrepender and linkHandler so you can add front-matter or rewrite cross-links.

Note

By default the generated docs end with an "Auto generated by spf13/cobra" tag (and man pages add a HISTORY section). Set DisableAutoGenTag: true on a command to omit it.

Warning

The tree generators may produce ambiguous filenames if your command names contain -. As the source notes: with a cmd that has subcommands sub and sub-third, where sub also has a child third, it is undefined which output lands in cmd-sub-third. Avoid - in command names if you generate per-command files.


12. Versioning, Help, and Error Output

Version flag

Set the Version field on your root command and Cobra adds a --version flag (and a -v shorthand, if free):

var rootCmd = &cobra.Command{
	Use:     "app",
	Version: "1.4.2",
}
app --version
app version 1.4.2

Customize the format with rootCmd.SetVersionTemplate(...).

Note

The --version flag and version template are tied to whichever command has a non-empty Version. A known limitation (community-reported) is that --version does not propagate to subcommands automatically — set Version on the specific command if you want app sub --version to work.

Help

Cobra adds a -h, --help flag to every command and a help command to any command that has subcommands. Override the default behavior with cmd.SetHelpFunc(...), cmd.SetHelpTemplate(...), cmd.SetUsageFunc(...), or cmd.SetUsageTemplate(...).

Quieting output

Field Effect
SilenceErrors: true Cobra does not print errors returned from RunE (you handle them).
SilenceUsage: true Cobra does not print the usage string after an error.
var rootCmd = &cobra.Command{
	Use:           "app",
	SilenceUsage:  true,   // don't dump usage on every runtime error
	SilenceErrors: false,
}

Tip

Setting SilenceUsage: true is almost always what you want once your CLI is stable. Without it, every runtime error (e.g. "file not found") prints the full usage text, which is noise for users who already know the command.

Custom error prefix

The default error prefix is Error:. Change it with cmd.SetErrPrefix("myapp:").

Helper: CheckErr

cobra.CheckErr(err) prints Error: <msg> to stderr and exits with code 1 if err is non-nil — a concise replacement for the if err != nil { ... os.Exit(1) } boilerplate in small programs.

func main() {
	cobra.CheckErr(rootCmd.Execute())
}

13. Global Behavior Toggles

These are package-level variables in the cobra package. Set them once (typically in init()) to change behavior program-wide.

Variable Default Effect
EnablePrefixMatching false Allow invoking a command by an unambiguous prefix of its name.
EnableCommandSorting true Sort commands alphabetically in help. Set false to keep insertion order.
EnableCaseInsensitive false Match command names and aliases case-insensitively.
EnableTraverseRunHooks false Run all persistent hooks along the command path (see §7).
MousetrapHelpText (a message) Text shown on Windows when the program is launched from Explorer. Set to "" to disable the splash.
MousetrapDisplayDuration 5 * time.Second How long that Windows message shows. 0 waits for the Enter key.
func init() {
	cobra.EnableCommandSorting = false
	cobra.EnablePrefixMatching = true
}

Caution

Cobra's own documentation warns that EnablePrefixMatching "can be a dangerous thing to automatically enable in CLI tools" — a new command added later could make a previously-unambiguous prefix ambiguous, silently changing behavior. Enable it deliberately.

Note

The mousetrap feature only affects Windows binaries launched by double-clicking in Explorer. It shows the help text so users realize the program is a command-line tool. It has no effect on Linux or macOS.


14. Common Recipes

A complete multi-command program

package main

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
)

var verbose bool

var rootCmd = &cobra.Command{
	Use:     "app",
	Short:   "App does useful things",
	Version: "1.0.0",
	SilenceUsage: true,
}

var serveCmd = &cobra.Command{
	Use:   "serve",
	Short: "Start the server",
	Args:  cobra.NoArgs,
	RunE: func(cmd *cobra.Command, args []string) error {
		port, _ := cmd.Flags().GetInt("port")
		fmt.Fprintf(cmd.OutOrStdout(), "listening on :%d\n", port)
		return nil
	},
}

func init() {
	rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
	serveCmd.Flags().IntP("port", "p", 8080, "port to listen on")
	rootCmd.AddCommand(serveCmd)
}

func main() {
	if err := rootCmd.Execute(); err != nil {
		os.Exit(1)
	}
}

Pass a context into commands

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	if err := rootCmd.ExecuteContext(ctx); err != nil {
		os.Exit(1)
	}
}

// inside a Run/RunE function:
RunE: func(cmd *cobra.Command, args []string) error {
	ctx := cmd.Context()   // the context passed to ExecuteContext
	return doWork(ctx)
}

Testing a command

func TestServe(t *testing.T) {
	buf := new(bytes.Buffer)
	rootCmd.SetOut(buf)
	rootCmd.SetArgs([]string{"serve", "--port", "9000"})
	if err := rootCmd.Execute(); err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(buf.String(), ":9000") {
		t.Errorf("unexpected output: %q", buf.String())
	}
}

SetArgs overrides os.Args[1:], and SetOut/SetErr capture output — together they make commands fully testable without spawning a process.


15. Troubleshooting

Error: required flag(s) "X" not set

Cause: A flag marked with MarkFlagRequired (or required as part of a one-required group) was not provided. Solution: Pass the flag, e.g. app serve --config app.yaml. Prevention: Document required flags in the command's Long/Example.

Error: unknown command "X" for "app"

Cause: The user typed a name that matches no subcommand or alias. Often a typo. Solution: Run app --help to list valid commands; Cobra usually prints a "Did you mean this?" suggestion. Prevention: Add common misspellings to a command's SuggestFor, or Aliases for legitimate alternates.

Error: if any flags in the group [a b] are set they must all be set; missing [b]

Cause: You used MarkFlagsRequiredTogether("a", "b") and supplied only one of them. Solution: Provide all flags in the group, or none. Prevention: Group only flags that are genuinely interdependent.

Error: if any flags in the group [a b] are set none of the others can be; [a b] were all set

Cause: MarkFlagsMutuallyExclusive("a", "b") and the user set more than one. Solution: Pass at most one of the mutually exclusive flags.

Panic: group id 'X' is not defined for subcommand 'app Y'

Cause: A subcommand has a GroupID whose group was never registered on the parent with AddGroup. Solution: Call parent.AddGroup(&cobra.Group{ID: "X", Title: "..."}) before adding the child. Prevention: Define groups and assign GroupIDs in the same init().

Panic: Command can't be a child of itself

Cause: You passed a command to its own AddCommand. Solution: Build distinct command values; don't add rootCmd to rootCmd.

PersistentPostRun / PostRun never runs

Cause: Post-run hooks are skipped when RunE (or an earlier *RunE) returns an error. (Community issue #1893.) Solution: Put unconditional cleanup in a defer inside RunE, not in a post-run hook.

Shell completion does nothing in bash

Cause: The bash-completion package is not installed, or the script was not sourced. Solution: Install bash-completion, then source <(app completion bash) and start a new shell.

Completion debugging

Cause: You want to see why a custom completion function returns nothing. Solution: Set the BASH_COMP_DEBUG_FILE environment variable to a writable path; Cobra (and your calls to cobra.CompDebugln) append debug logs there during completion.

export BASH_COMP_DEBUG_FILE=/tmp/app-comp.log

--version works on the root but not a subcommand

Cause: The version flag is added only to the command whose Version field is non-empty. (Community issue #1860.) Solution: Set Version on the specific subcommand if you need app sub --version.


16. FAQ

Q: Is Cobra a program I install and run, or a library? It is a Go library. You import github.com/spf13/cobra and build your own binary with it. There is no cobra executable to run your commands.

Q: Do I have to use Run or can I return errors? Use RunE, which returns an error. Cobra prints the error consistently and Execute() returns it so your main can set the exit code. Run (no error) is fine only for commands that cannot fail.

Q: What is the difference between Flags() and PersistentFlags()? Flags() defines a flag local to one command. PersistentFlags() defines a flag that is also inherited by all of that command's descendants. Use persistent flags for cross-cutting options like --verbose on the root.

Q: How do I make a flag required? cmd.MarkFlagRequired("name") for a local flag, or cmd.MarkPersistentFlagRequired("name") for a persistent one. Cobra then errors if it is missing.

Q: How do positional arguments differ from flags? Flags are named (--port 80); positional arguments are the leftover values after flags are removed. Validate their count/values with the Args field (e.g. cobra.ExactArgs(1)).

Q: Where does my command read its arguments? From the args []string parameter of Run/RunE — it contains the validated positional arguments after the command name and flags.

Q: How do I add tab completion? You don't have to write any scripts — every Cobra program already has a completion command for bash/zsh/fish/PowerShell. To complete argument or flag values, supply ValidArgs, a ValidArgsFunction, or RegisterFlagCompletionFunc.

Q: Can I generate man pages or Markdown docs from my commands? Yes. Import github.com/spf13/cobra/doc and call GenManTree, GenMarkdownTree, GenReSTTree, or GenYamlTree.

Q: In what order do the Run hooks fire? PersistentPreRun → PreRun → Run → PostRun → PersistentPostRun. The E variant takes precedence over the non-E form when both are set.

Q: Why do my root command's persistent pre-run hooks stop firing when a subcommand also defines one? By default only the first persistent hook found while walking the tree runs. Set cobra.EnableTraverseRunHooks = true to run all of them along the path.

Q: How do I stop Cobra from printing usage on every error? Set SilenceUsage: true (and optionally SilenceErrors: true to handle error printing yourself).

Q: How do I pass a context.Context into my commands? Call rootCmd.ExecuteContext(ctx) and read it inside a command with cmd.Context().

Q: Can I invoke a command by a shortened name? Set cobra.EnablePrefixMatching = true to allow unambiguous prefixes. Use with care — adding commands later can make a prefix ambiguous.


17. Quick Reference

Execution entry points

Call Purpose
cmd.Execute() Run the command tree from the root using os.Args[1:].
cmd.ExecuteContext(ctx) Execute with a context attached.
cmd.ExecuteC() Execute and also return the matched command.
cobra.CheckErr(err) Print Error: ... and os.Exit(1) if err != nil.

Defining structure

Call Purpose
parent.AddCommand(child...) Attach subcommands.
parent.AddGroup(&cobra.Group{...}) Register a help group.
cmd.SetArgs([]string{...}) Override the args (testing).
cmd.SetOut/SetErr/SetIn(...) Redirect I/O streams.

Flags

Call Purpose
cmd.Flags() Local flag set.
cmd.PersistentFlags() Inherited flag set.
cmd.MarkFlagRequired("f") Require a flag.
cmd.MarkFlagsRequiredTogether(...) All-or-none flag group.
cmd.MarkFlagsOneRequired(...) At-least-one flag group.
cmd.MarkFlagsMutuallyExclusive(...) At-most-one flag group.
cmd.MarkFlagFilename("f", exts...) Complete files by extension.
cmd.MarkFlagDirname("d") Complete directories.

Argument validators

NoArgs · ArbitraryArgs · MinimumNArgs(n) · MaximumNArgs(n) · ExactArgs(n) · RangeArgs(min,max) · OnlyValidArgs · NoDuplicateArgs · MatchAll(...)

Completion

Call Purpose
cmd.ValidArgsFunction = fn Dynamic argument completion.
cmd.RegisterFlagCompletionFunc("f", fn) Flag-value completion.
cobra.NoFileCompletions Disable file completion.
cobra.FixedCompletions(choices, dir) Always return the same list.
cobra.AppendActiveHelp(comps, msg) Add an Active Help message.

Documentation generators (doc package)

GenManTree · GenMarkdownTree · GenReSTTree · GenYamlTree (each with a *Custom variant)

Environment variables (consumed at runtime)

Variable Effect
BASH_COMP_DEBUG_FILE Path for completion debug logs.
COBRA_ACTIVE_HELP=0 Disable Active Help globally.
<PROGRAM>_ACTIVE_HELP=0 Disable Active Help for your program.
<PROGRAM>_COMPLETION_DESCRIPTIONS=false Turn off completion descriptions.