Customizing Your CLI

In this tutorial, we’ll build upon the basic CLI from the previous tutorial and add customization features like flags, custom descriptions, and configuration options.

Prerequisites

  • Completed the My First CLI tutorial
  • Your my-cli project from the previous tutorial

Steps

  1. Customize the Root Command Description

    Let’s start by updating the main application description. Open the cmd/root.go file and see how we transform a basic command into a professional one:

    Before
    var rootCmd = &cobra.Command{
         Use:   "my-cli",
         Short: "A brief description of your application",
         Long: `A longer description that spans multiple lines and likely contains
       examples and usage of using your application. For example:
    
       Cobra is a CLI library for Go that empowers applications.`,
         // Uncomment the following line if your bare application
         // has an action associated with it:
         // Run: func(cmd *cobra.Command, args []string) { },
       }
    After
    var rootCmd = &cobra.Command{
         Use:   "my-cli",
         Short: "A powerful CLI tool built with Cobra",
         Long: `My CLI is a demonstration application built with Cobra.
       
       This application shows how to create professional command-line
       tools with proper flag handling, subcommands, and configuration.`,
         // Uncomment the following line if your bare application
         // has an action associated with it:
         // Run: func(cmd *cobra.Command, args []string) { },
       }
  2. Add Global Flags

    Let’s see how adding global flags transforms your CLI from basic to feature-rich. Here’s how the init() function evolves:

    Before
    func init() {
         rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
       }
    After
    var verbose bool
       
       func init() {
         rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output")
         rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
       }
  3. Enhance the Serve Command

    Watch how a simple serve command evolves into a fully-featured server command with flags and verbose output:

    Before
    var serveCmd = &cobra.Command{
         Use:   "serve",
         Short: "A brief description of your command",
         Long: `A longer description that spans multiple lines and likely contains
       examples and usage of using your command.`,
         Run: func(cmd *cobra.Command, args []string) {
           fmt.Println("serve called")
         },
       }
       
       func init() {
         rootCmd.AddCommand(serveCmd)
       }
    After
    var port int
       var host string
       
       var serveCmd = &cobra.Command{
         Use:   "serve",
         Short: "Start the application server",
         Long: `Start the application server on the specified host and port.
       
       The serve command will start a web server that can handle requests
       and provide API endpoints for your application.`,
         Run: func(cmd *cobra.Command, args []string) {
           if verbose {
             fmt.Printf("Starting server on %s:%d\n", host, port)
             fmt.Println("Verbose mode enabled")
           } else {
             fmt.Printf("Server starting on %s:%d\n", host, port)
           }
         },
       }
       
       func init() {
         rootCmd.AddCommand(serveCmd)
         serveCmd.Flags().IntVarP(&port, "port", "p", 8080, "Port to run the server on")
         serveCmd.Flags().StringVarP(&host, "host", "H", "localhost", "Host to bind the server to")
       }
  4. Test Your Enhanced CLI

    Build and test your updated CLI:

    go build -o my-cli
    ./my-cli --help
    A powerful CLI tool built with Cobra
    My CLI is a demonstration application built with Cobra.
    This application shows how to create professional command-line
    tools with proper flag handling, subcommands, and configuration.
    Usage:
    my-cli [command]
    Available Commands:
    completion  Generate the autocompletion script for the specified shell
    help        Help about any command
    serve       Start the application server
    Flags:
    -h, --help      help for my-cli
    -t, --toggle    Help message for toggle
    -v, --verbose   verbose output
  5. Test the Serve Command with Flags

    Try out the serve command with different flag combinations:

    ./my-cli serve --help
    Start the application server on the specified host and port.
    The serve command will start a web server that can handle requests
    and provide API endpoints for your application.
    Usage:
    my-cli serve [flags]
    Flags:
    -h, --help          help for serve
    -H, --host string   Host to bind the server to (default "localhost")
    -p, --port int      Port to run the server on (default 8080)
    Global Flags:
    -v, --verbose   verbose output

    Test with custom port and verbose mode:

    ./my-cli serve --port 3000 --host 0.0.0.0 --verbose
    Starting server on 0.0.0.0:3000
    Verbose mode enabled
  6. Add Input Validation

    See how adding validation transforms your command from basic functionality to production-ready code:

    Before
    Run: func(cmd *cobra.Command, args []string) {
         if verbose {
           fmt.Printf("Starting server on %s:%d\n", host, port)
           fmt.Println("Verbose mode enabled")
         } else {
           fmt.Printf("Server starting on %s:%d\n", host, port)
         }
       },
    After
    Run: func(cmd *cobra.Command, args []string) {
         if port < 1 || port > 65535 {
           fmt.Fprintf(os.Stderr, "Error: port must be between 1 and 65535\n")
           os.Exit(1)
         }
         
         if verbose {
           fmt.Printf("Starting server on %s:%d\n", host, port)
           fmt.Println("Verbose mode enabled")
           fmt.Println("Configuration validated successfully")
         } else {
           fmt.Printf("Server starting on %s:%d\n", host, port)
         }
       },

Summary

In this tutorial, you’ve learned how to:

  • Customize command descriptions with the Short and Long fields
  • Add global flags that work across all commands using PersistentFlags()
  • Create command-specific flags with Flags()
  • Use different flag types (bool, int, string)
  • Implement flag shortcuts with single letters
  • Add basic input validation
  • Access global flags from subcommands

Your CLI now has proper help text, configurable options, and professional command-line behavior!

Next Steps

  • Try adding more commands with cobra-cli add [command-name]
  • Explore configuration files with Viper integration
  • Add persistent configuration and environment variable support