DEV Community

Cover image for Cobra in Go: How to Create Easy-to-Use Command-Line Tools
Rijul Rajesh
Rijul Rajesh

Posted on

Cobra in Go: How to Create Easy-to-Use Command-Line Tools

Ever wondered how all the popular CLI tools work? They are all designed in a way that makes them easy and convenient to use.

In this article, I will show you the Cobra library in Go, used for building CLI systems with ease!

What is Cobra?

Cobra is basically a Go library to build command-line interfaces, for example, docker run -d nginx.

Cobra gives you the following:

  • Commands & subcommands
  • Flags (--name, -n)
  • Help text
  • Shell completion
  • Cleaner structure

The mental model behind Cobra

You can think of the CLI interface like the tree below:

cli-tool
├── view
│   ├── --action
│   └── --format
├── run
│   └── --job-id
└── version
Enter fullscreen mode Exit fullscreen mode

Each node in this tree is a command.
So this gives you the following:

  • cli-tool
  • cli-tool view
  • cli-tool view --action
  • cli-tool view --format
  • cli-tool run
  • cli-tool run --job-id
  • cli-tool version

Getting Cobra on your machine

You can get this library via the following command:

go get github.com/spf13/cobra@latest

Enter fullscreen mode Exit fullscreen mode

Quick example to understand the needful

Creating the root command

Consider the following main.go file:

package main

import "mycli/cmd"

func main() {
    cmd.Execute()
}
Enter fullscreen mode Exit fullscreen mode

In cmd/root.go:

package cmd

import (
    "fmt"
    "os"

    "github.com/spf13/cobra"
)

var rootCmd = &cobra.Command{
    Use:   "mycli",
    Short: "MyCLI is a demo tool",
    Long:  "MyCLI is a demo CLI application built using Cobra",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Hello from root command")
    },
}

func Execute() {
    if err := rootCmd.Execute(); err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
}
Enter fullscreen mode Exit fullscreen mode

When you run this:

go run main.go
Enter fullscreen mode Exit fullscreen mode

You will get the result from the root command, since there aren't any subcommands:

Hello from root command
Enter fullscreen mode Exit fullscreen mode

Creating the subcommand

Now let's add a subcommand.

cmd/version.go

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

var versionCmd = &cobra.Command{
    Use:   "version",
    Short: "Print the version",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("mycli version 1.0.0")
    },
}

func init() {
    rootCmd.AddCommand(versionCmd)
}
Enter fullscreen mode Exit fullscreen mode

You can notice that versionCmd is added to rootCmd. That is how the hierarchy is set up.

Now, if you run the command:

go run main.go version
Enter fullscreen mode Exit fullscreen mode

Output

mycli version 1.0.0
Enter fullscreen mode Exit fullscreen mode

Creating a subcommand within a subcommand, and adding flags

We can nest the commands as much as we like, so let's create a view subcommand.

We will also provide an option to use flags.

cmd/view.go

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

var someFlag bool

var viewCmd = &cobra.Command{
    Use:   "view",
    Short: "View data",
    Run: func(cmd *cobra.Command, args []string) {
        // This runs ONLY when no subcommand is provided
        fmt.Println("view command executed")
        fmt.Println("someFlag:", someFlag)
    },
}

func init() {
    // Flag for: mycli view --someflag
    viewCmd.Flags().BoolVar(
        &someFlag,
        "someflag",
        false,
        "Enable special behavior",
    )

    rootCmd.AddCommand(viewCmd)
}
Enter fullscreen mode Exit fullscreen mode

Here viewCmd.Flags().BoolVar(...) Creates a local flag attached to view.

Run executes only if no further subcommands are provided.

The subcommand for view is defined here.

cmd/view_count.go

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

var viewCountCmd = &cobra.Command{
    Use:   "count",
    Short: "Count records",
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Counting records...")
    },
}

func init() {
    viewCmd.AddCommand(viewCountCmd)
}
Enter fullscreen mode Exit fullscreen mode

So, based on the above, this is how Cobra behaves:

Command What runs
mycli view viewCmd.Run
mycli view --someflag viewCmd.Run
mycli view count viewCountCmd.Run
mycli view count --someflag flag NOT available

Wrapping up

So that is some of the basics of the Cobra framework.

You can find the example in this repository under the following path:

https://github.com/RijulTP/blog-examples/tree/main/cobra-blog/mycli

It is very handy when you are designing a CLI tool for the first time, as it puts a solid foundation in place for you to work on.

If you have read till here, I have another handy resource for you.

If you’ve ever struggled with repetitive tasks, obscure commands, or debugging headaches, this platform is here to make your life easier. It’s free, open-source, and built with developers in mind.

👉 Explore the tools: FreeDevTools
👉 Star the repo: freedevtools

Top comments (0)