Building CLI applications in Go with Cobra

While GUIs can offer a nicer-looking interface and better user experience, command line (CLI) applications are still prevalent due to their simplicity, performance, and speed. In this article, we’ll dive into how you can get started building your own CLI application in Go with Cobra.

What to know about building CLI applications

Popular applications that use the command-line interface include Git, Docker, Kubernetes, and Homebrew. The command-line interface interacts with the operating system directly via a command shell. 

Many programming languages like Go provide functionality for building CLI applications. In Go, you can use the flag package to build CLI applications without dependencies. You can also use the popular Cobra package, which is used in popular projects like Docker, Arduino, Github CLI, Kubernetes, Hugo, and Twitch. The Cobra package provides a simple interface for building command-line applications in Go fast with flexibility via the cobra-cli binary, which generates CLI apps and files that you need to integrate the Cobra package into your applications.

Getting started with the Cobra package 

With Go installed, use the following command to install Cobra in your Go workspace (~/go by default):

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

You’ll need to set your $GOPATH environment variable in your Bash to use the cobra-cli package. Next, create and enter a new directory for your project in your $GOPATH/src directory (~/go/src by default). I’ll call mine teachingCobra:

$ mkdir teachingCobra && cd teachingCobra

Run these commands to initialize your new Cobra application:

$ go mod init teachingCobra
$  cobra-cli init 

The command above will generate some files in your workspace, as shown below:

The root.go file in the cmd directory contains the root command that runs when your CLI application is called. The generated main.go file has the main function, the application’s entry point. 

You’ll need to build and install your CLI application whenever you make changes. You can use the build command to build the application.

$ go build  

Then you can use the ./teachingCobra command to use your locally compiled command. Or you can install the application with the install command, which builds and installs the application to your Go binaries folder so you can use it anywhere:

$ go install  

Now, let’s examine the anatomy of a CLI command to help you understand the various parts of a CLI application you can build.

Anatomy of a CLI command 

As a Go developer, you’re familiar with the go CLI and at least the get command for installing packages and modules to your workspace. Another popular command-line tool you may be familiar with is the Git CLI for version control and making commits using the commit command:

$ git commit -m "made changes to the main branch." 

Every command-line tool uses the application name, commands, flags, and/or arguments.

Commands trigger specific functionalities of the application, and arguments are optional parameters on commands for the command’s functionalities. This functionality can be further modified with flags. Commands may support any combination of arguments and/or flags.

The root command of your CLI application 

When you use the name of your application without additional commands and flags, the root command gets executed. To initialize a CLI application using the cobra-cli init command on your workspace, the root.go file in the cmd directory contains the code for the root command of your application. Here’s the code generated by Cobra for the root command:

The Use field is initialized with the name of your application; you can change it if you choose to rename your application. The Short field should be a one-line (roughly 80 character) description of your app, and the Long field should be a longer description. The Short and Long fields are used with the help command and flags that are added to your application by default. 

The Run field is the function that is triggered when the command is used.

More commands can be added to your application in a similar format as the root command, and you can configure them based on the command’s functionality.

Adding commands to your CLI application 

You don’t need to create a new file or function by hand to add commands to your application. You can use the cobra-cli add command to create a new command on your initialized application. For example, let’s add a command called new:

$ cobra-cli add new

The add command creates a new command for your initialized cobra-cli application and adds a file to your cmd folder. The file contains the code for executing the command, and you can make changes to the file based on the functionalities of the command.

The new command has been added to the initialized application. In this case, the app’s name is teachingCobra. You can execute the new command by specifying it alongside your application name.

$ teachingCobra new 

The code in the new command file is the same as the code in the root command, and just like the root command, you can change the configurations of your new command and add a function body to the Run field.

Working with arguments on your CLI app 

Your application might require some user input to function; Cobra also makes it easy to work with arguments. The arguments are passed via the args parameter as an array of strings to the Run field’s function, and you can access them individually via indexes on the array.

For example, the following command interacts with provided arguments:

Run: func(cmd *cobra.Command, args []string) { 
         if len(args) < 1 { 
           log.Fatal("You didn't specify the additional arguments\Use the --help flag for comprehensive help on how to use this tool") } 
         argument := args[0] 
         fmt.Println(argument) 
}

In the Run field above, the conditional statement checks if there are any arguments and quits the program when there are none. If there are arguments, the program continues and the first argument is passed to the argument variable and printed out. You can try this command out in your own CLI. You may need to import the log module in the command file.

Adding flags to your CLI app 

If you’re building an application and require your users to choose from a variety of options by specification, you’ll find using flags handy for your command line application. Ideal flags are short and easy to remember. 

You can add persistent flags (available to any command and all of its subcommands) or local flags assigned to only a specified command. You can think of persistent flags as being inherited by all subcommands. Let’s define flags and configurations in the init function of the new command file you created via Cobra.

Adding persistent flags to your CLI application 

Want to add a flag to the new command? newCmd has a method called PersistentFlags you can utilize, indicating the parameters via a returned String method:

func init(){ 
    newCmd.PersistentFlags().String("talk", "", "talk to the new command") 
} 

The String method takes several arguments to initialize the flag. First is the name, second is the default value, and third is a description. In this case, the flag is talk, the default value is an empty string, and the description is “talk to the new command.” 

cmd has a method called Flags you can use with GetString to fetch the flag’s provided argument. Once you have the user’s input, you can perform any necessary checks on the response:

Run: func(cmd *cobra.Command, args []string) { 
talker, _ := cmd.Flags().GetString("talk") 
if talker == "hello" { 
   fmt.Println("hi") 
} else if talker == "hi" { 
   fmt.Println("hello") 
} 
}

In the code example, you anticipated that the value passed to the flag is either hello or hi, and then the other value is printed out in response. 

Adding local flags to your CLI application 

You can add local flags to your CLI application using the command’s BoolP method of the Flags method. The BoolP method takes in the flag name, the flag shorthand, the value, and the usage of the flag:

newCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") 

The flag shorthand, in this case t, should be one or two characters at most. You can access and use the local flag the same way you can access inputs from persistent flags using the GetString method. As a boolean via the BoolP method, this flag defaults to false but becomes true if the flag is present in the command.

Learn more about building applications in Go 

The Cobra package is a handy tool; you can build your business logic for your application and quickly build the CLI application itself within minutes since the Cobra package provides all the framework you need. 

This tutorial has taught you how to build command-line applications in Go using Cobra, from adding commands to receiving user input using arguments and options using flags.

Interested in learning more about building applications in Go? Here are some additional tutorials you might want to check out:

This blog post was created as part of the Mattermost Community Writing Program and is published under the CC BY-NC-SA 4.0 license. To learn more about the Mattermost Community Writing Program, check this out.

Read more about:

CLI apps Go

Ukeje Goodness is a Go developer building backend applications and exploring Go.