# cobra: subcommands, POSIX flags and generated completions for Go

> spf13/cobra is a Go library that gives a command line application a command tree, POSIX flags, generated help, shell completion and man pages, and it is what Kubernetes, Hugo and the GitHub CLI are built on. It has four direct dependencies, a go 1.15 language floor, and no tag newer than 2025-12-04.

**spf13/cobra** — GitHub describes it as A Commander for modern Go CLI interactions. The repository metadata lists Go as its primary language. The metadata lists the Apache-2.0 license. This article stays within the project description and details documented in the GitHub repository README.

- Repository: https://github.com/spf13/cobra
- Website: https://cobra.dev
- Stars: 44,674 · Forks: 4,623
- Language: Go
- License: Apache-2.0
- Published: 2026-08-13 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/spf13-cobra

## Everything hangs off Command, and the target shape is APPNAME VERB NOUN

Cobra is built on three things: commands represent actions, args are the things, and flags modify the action. The pattern the project asks you to aim for is APPNAME VERB NOUN --ADJECTIVE, or APPNAME COMMAND ARG --FLAG, and the two examples it uses are both commands you already know:

```go
import "github.com/spf13/cobra"
```

In hugo server --port=1313, server is the command and port is the flag. In git clone URL --bare, clone is the command and bare is a flag. Commands nest, and a command can carry an action to run.

Two of the features come from that structure rather than from a template. Command aliases let you rename a command while keeping the old spelling working, which is how a CLI changes a name without breaking anyone's script. Intelligent suggestions turn a typo into a hint, so app srver prints a did you mean app server question, and that behaviour comes from the library rather than from anything you write. The cost is the machinery: a single verb with three flags does not need a command tree, and adopting cobra for one means paying for the structure you are not using.

## The module declares go 1.15 and four direct dependencies

The dependency list is short enough to read in one go, which is the first thing to check when evaluating a CLI framework:

```go
require (
	github.com/cpuguy83/go-md2man/v2 v2.0.6
	github.com/inconshreveable/mousetrap v1.1.0
	github.com/spf13/pflag v1.0.9
	go.yaml.in/yaml/v3 v3.0.4
)
```

Two of those are the machinery. spf13/pflag is a fork of the Go flag standard library that keeps the same interface and adds POSIX compliance, which is where cobra's short and long flag forms come from. go-md2man is what turns your command definitions into man pages. The other two, mousetrap and go.yaml.in/yaml/v3, are support.

The line above them is the one to look at twice. The module declares go 1.15, a language floor from before generics, while the repository is still receiving commits. That keeps the library buildable on old toolchains, and it also means the code cannot reach for newer language or standard library features without raising the floor and breaking anyone still on an old Go.

## make runs gofmt and go test, and never builds a binary

The Makefile is small enough to read, and its shape tells you what kind of repository this is. The default target is all, and all is fmt test. There is no build target at all, because there is nothing to build: cobra is a library, and the artifacts a user runs come from whatever application imports it.

Formatting is a gate rather than a fix. The fmt target runs gofmt over every .go file it finds, and if gofmt reports any difference it prints the diff and exits non-zero, so a misformatted file fails the build rather than being rewritten. The test target depends on install_deps, and install_deps runs go get -v ./... before go test -v ./... runs.

That dependency order is the detail worth knowing. Running the tests mutates your module files first, and on a machine without network access or with a module cache that is not warm, the failure you see is from go get rather than from a test. Linting is a separate target that runs golangci-lint, and golangci-lint is not a module dependency, so the Makefile warns at parse time with a curl one-liner if it is not on your PATH.

## Two generations of bash completion live in the same tree

Look at the root and the shell support is one file per shell, plus a shared one: bash_completions.go, fish_completions.go, powershell_completions.go, zsh_completions.go and shell_completions.go. Each has a test beside it. Then there is bash_completionsV2.go, with bash_completionsV2_test.go, which is a second implementation of the same job for the same shell.

The README promises automatically generated shell completion for bash, zsh, fish and powershell, and does not say which bash generator applies to your application. For a consumer that only matters when the generated script behaves differently than expected and the fix is not obvious, and for a contributor it means changes to completion behaviour may need to be made in two places.

The rest of the root is single-purpose files, which is the shape of a library with a small API and a lot of surface: args.go, command.go, cobra.go, completions.go and flag_groups.go each carry a test. Two of them split by operating system, command_win.go and command_notwin.go, which is where the Windows-specific path lives.

## pflag is why the flags are POSIX, and mousetrap is why Windows gets a message

Cobra does not implement flag parsing. Flag functionality is provided by the pflag library, described as a fork of the flag standard library that maintains the same interface while adding POSIX compliance, and cobra requires pflag v1.0.9. That is the source of the fully POSIX-compliant flags with short and long versions, and it is the reason global, local and cascading flags behave the way they do across nested subcommands.

There is a practical consequence for anyone arriving from the standard library. If your project already uses pflag, cobra's flags are the same types and nothing changes. If it uses the stdlib flag package, switching to cobra also switches the flag implementation under you, and any code that reached into the flag set has to be checked.

mousetrap v1.1.0 is the other dependency worth understanding, and it is a Windows-only one, which the command_win.go and command_notwin.go split reflects. It exists for the case where someone double-clicks a console binary on Windows and the window closes before they can read anything, so a message has to be shown instead. On a non-Windows build that file is not compiled at all.

## The scaffolder lives in another repository and moves on its own schedule

There are two ways in, and the README is explicit that the second is the easy one. The library route is one command:

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

The generator route installs a separate program, cobra-cli, which bootstraps your application scaffolding and creates the command files:

```bash
go install github.com/spf13/cobra-cli@latest
```

Those are different repositories with different version numbers, and nothing couples them. Installing the generator at latest gives you whatever the generator is today, and the code it writes imports the library at whatever version you later pin in your go.mod. When a flag or an API moves between cobra releases, generated code can be behind the library you are compiling against, and the README sends you to the Cobra Generator README in the other repository for the details.

The documentation splits the same way. The user guide is a file inside this repository at site/content/user_guide.md, the extensive documentation is on cobra.dev, and the generator has its own README. Three places to look, two of which can describe different versions.

## No tag since 2025-12-04, and a Warp block in the README

The release history is short and dated. v1.10.0 and v1.10.1 were both published on 2025-09-01, three hours apart, and v1.10.2 followed on 2025-12-04. The last push to the default branch, main, was on 2026-07-11, and the repository is not archived.

So the newest tag is roughly ten months old and master is about seven months ahead of it. For a library whose dependency list is four modules, pinning v1.10.2 is a reasonable choice, and so is tracking main, but they are not the same code. The two same-day patch releases in September also suggest a fix was cut and then amended within hours, which is normal for a widely used library and is a reason to read a patch note before assuming v1.10.0 and v1.10.1 behave alike.

One more thing sits in the README above the overview: a supported-by block for Warp, the terminal, with a link to try it. Sponsorship is placed at the top of the file, which is a small reminder that a popular library's README is partly a front door for someone else's product.

## Conclusion

cobra fits a Go team writing a multi-command tool that needs help text, shell completion and man pages without maintaining them by hand, and four direct dependencies make it cheap to adopt. It does not fit a single-command script, where the command tree costs more than it returns. Verify first which version you can live with, because the newest tag is v1.10.2 from 2025-12-04 while the last push to main was on 2026-07-11, leaving the tagged line and master seven months apart.

## FAQ

### How do I install cobra in a Go project?

Run go get -u github.com/spf13/cobra@latest and then import "github.com/spf13/cobra" in your code. If you would rather start from generated scaffolding, go install github.com/spf13/cobra-cli@latest installs a separate program that creates the application and command files for you.

### What does cobra do for a CLI application?

It supplies the command tree with nested subcommands, POSIX-compliant flags through pflag, automatic help for commands and flags with -h and --help recognised, generated shell completion for bash, zsh, fish and powershell, generated man pages, command aliases for renaming without breaking, and typo suggestions such as app srver pointing at app server.

### What Go version does cobra require?

The go.mod in the repository declares go 1.15, and its four direct dependencies are go-md2man/v2 v2.0.6, inconshreveable/mousetrap v1.1.0, spf13/pflag v1.0.9 and go.yaml.in/yaml/v3 v3.0.4. That language floor is well below the current toolchain even though the repository is still being committed to.

### Does cobra depend on viper?

No. The integration with viper is described as optional and aimed at 12-factor apps, and viper does not appear in the go.mod require list. Flag handling comes from spf13/pflag, a fork of the Go flag package that keeps the same interface while adding POSIX compliance.

### How do I run the cobra tests?

The Makefile default target is all, which is fmt test. Formatting is checked with gofmt and fails if any file differs, and the test target depends on install_deps, which runs go get -v ./... before go test -v ./... executes. Linting is a separate target and needs golangci-lint on your PATH, since it is not a module dependency.

## Sources

- [Official documentation](https://cobra.dev)
- [Official README](https://github.com/spf13/cobra#readme)
- [Project repository](https://github.com/spf13/cobra)
- [Release notes](https://github.com/spf13/cobra/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/spf13-cobra
