Please purchase the course to watch this video.

Full Course
Cobra is a widely-used Go library for building robust command-line (CLI) applications, offering features like subcommands, nested commands, and customizable help messages, and powering tools such as Kubernetes and the GitHub CLI. Leveraging Cobra streamlines the process of structuring CLI apps by allowing developers to generate commands—like create, read, update, and delete operations for resources—using either the Cobra CLI tool or manual setup. The CLI tool expedites the boilerplate setup and supports aliases, auto-completion, and efficient organization of commands and subcommands. By properly utilizing Cobra’s command hierarchy and built-in features like persistent flags and the RunE method for error handling, developers can quickly build clear, user-friendly, and extensible CLI tools suitable for complex applications like a CMS.
In this lesson, we're going to take a look at one of the most popular packages when it comes to building CLI applications in Go. That package is Cobra, which is a library for creating modern CLI applications in Go, and is used through many different Go projects, including:
- Kubernetes
- Hugo
- GitHub CLI
We've already taken a look at what Cobra provides in earlier modules in this course, specifically the ability to have sub-command-based CLIs, which you can see here, such as app server
, app fetch
, etc.
Our CMS Implementation
In our case, we're going to use Cobra in order to create various different sub-commands to perform create, read, update, and delete operations on our CMS system.
However, Cobra can also be used for more than just this, including:
- Fully POSIX-compliant flags
- Nested sub-commands (which we'll take a look at)
- Global and local and cascading flags
- And other features as well
Installation Approaches
Before we jump into all of those different concepts throughout this module, let's begin by using Cobra in order to set up our few root commands. In order to do so, we have a couple of different approaches we can take:
- Manual Implementation: Manually implement Cobra into our application (which I actually prefer to do in my own time)
- Cobra CLI: Use the Cobra CLI in order to be able to add Cobra into our application in an idiomatic way
For this course and this module, we're going to use the Cobra CLI, but we will take a look at the code that it generates, and I'll also show you some code on how I like to use Cobra as well, because I prefer a bit more of a functional approach.
Installing the Cobra CLI
In order to begin, let's first install the Cobra CLI onto our system, which you can do by copying the command that's provided by the Cobra documentation and running it inside of a terminal:
go install github.com/spf13/cobra-cli@latest
Upon doing so, you should then have Cobra installed, and you should have the cobra-cli
command available to you.
Now, if we go ahead and quickly run the Cobra CLI with the help flag:
cobra-cli --help
You can see that it provides four available commands. By the way, the Cobra command itself actually uses Cobra under the hood, and as you can see, it provides a really nice help message by default, as well as all of the flags that you can actually use.
Initializing Cobra in Our Project
Let's go ahead and run the Cobra CLI with the init
command, and we'll pass in the --author
flag as well:
cobra-cli init --author "dreamsofcode"
With that, our Cobra CMS should now be applied. And if I go ahead and run the git status
command, you can see that Cobra has made some modifications to my code, as well as adding in some untracked files.
Important: This is one of the reasons why you want to make sure you only run Cobra on a file or a repository that already has git set up, because it will make some breaking changes.
Understanding the Generated Code
main.go Changes
If we go ahead and run the git diff
command on the main.go
, you can see here it's added in the copyright dreams of code, but it's also gone about making the other changes, such as getting rid of the fmt.println
that we had before for "Hello CMS".
package main
import "github.com/dreamsofcode-io/cli-cms/cmd"
func main() {
cmd.Execute()
}
The cmd Package
If we go inside the cmd
package, you can see we have a root.go
, which again has my copyright at the top with my author name. But inside, you can see it's setting up a Cobra command as the root command.
var rootCmd = &cobra.Command{
Use: "cli-cms", // Let's change this to just "cms"
Short: "A brief description of your application",
Long: `A longer description...`, // We'll update this
}
Let's go ahead and make this change now:
var rootCmd = &cobra.Command{
Use: "cms",
Short: "A simple application for managing blog posts",
// Long: (we'll remove this for now)
}
The Execute Function
You can see here there's the execute
function. This is where it's calling the rootCmd.Execute()
and what we're calling inside of our main function:
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
Adding Subcommands
However, we want to go ahead and actually add a few commands in order to be able to implement create, read, update and delete actions when it comes to our CMS project.
Let's commit our current changes first:
git add .
git commit -m "Cobra root command added"
Adding the Posts Resource Command
Let's go ahead and add our first sub command using the Cobra CLI command:
cobra-cli add posts --author "dreamsofcode"
This creates a new file cmd/posts.go
. Let's examine and modify it:
var postsCmd = &cobra.Command{
Use: "posts",
Short: "Used to manage the posts resource",
// We'll remove the Run function since we don't want an action for the posts command itself
}
Now if we run our application:
go run . --help
You can see we have the posts
command available. And if we run:
go run . posts --help
You can see: "Used to manage the posts resource."
Adding the Create Subcommand
Let's go ahead and create a new create sub command inside of our posts resource:
cobra-cli add create --parent posts --author "dreamsofcode"
This creates cmd/create.go
. Let's modify it:
var createCmd = &cobra.Command{
Use: "create",
Short: "Used to create a new post",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println("post create called")
return nil
},
}
func init() {
postsCmd.AddCommand(createCmd) // Note: it's postsCmd, not posts
}
Now we can test our nested commands:
go build .
./cms posts create
Output: "post create called"
Adding Command Aliases
We can also add aliases to make commands more natural. For example, to allow both create
and add
:
var createCmd = &cobra.Command{
Use: "create",
Aliases: []string{"add"},
Short: "Used to create a new post",
RunE: func(cmd *cobra.Command, args []string) error {
fmt.Println("post create called")
return nil
},
}
Now both of these work:
./cms posts create
./cms posts add
Homework Tasks
Before we move on and start looking at some of the power of Cobra, I'm going to go ahead and set some homework for you:
1. Create More Sub Commands
Create the following sub commands under posts
:
posts list
- Used to list all of the posts that we have available to usposts get
- To get a single post (we'll add a flag to this in the future)posts delete
- Or you could call itremove
if you want, whichever feels more naturalposts update
- Orposts edit
- Used for editing or updating posts
Feel free to use aliases to define both variations (e.g., delete
/remove
, update
/edit
).
2. Use RunE Instead of Run
Check out the RunE
property, which is very similar to the Run
property, allowing you to define an action, but also allows you to return an error. This means if something goes wrong, you can return it up the call chain and it will eventually make its way to the root command's execute function, so you can log out what actually went wrong.
For me, the RunE
field makes a lot more sense as we're going to want to return errors in case something goes wrong, either with our user validation or when we try to insert a record into the database we're going to choose later on.
Make sure to use the RunE
field when you specify your various different commands.
Next Steps
After that, we then should be in a good space to move on to the next lesson. I will go and add all of the commands that I want to add in my own time, and we'll start off from the next lesson where we have all of our commands for the different actions defined.
Then we're going to go ahead and start looking at the create command in order to be able to create a new post with various properties that we can pass in.
Key Takeaways
- Cobra is the most popular CLI package for Go, used by major projects
- The Cobra CLI makes it easy to scaffold CLI applications
- Commands can have nested subcommands for complex functionality
- Aliases allow multiple ways to invoke the same command
RunE
is preferred overRun
for proper error handling- Cobra automatically generates help messages and usage information
No homework tasks for this lesson.