Cobra and Viper Quickstart
Cobra & Viper Quickstart
Cobra
Cobra is a library for building CLI applications with commands, subcommands, and flags.
Install
1go get -u github.com/spf13/cobra/cobraStructure
A typical Cobra project separates each command into its own file under a cmd/ directory.
cmd/
root.go # root command
serve.go # subcommand
main.gomain.go
The entrypoint simply calls into the cmd package. All CLI logic lives there.
1package main
2
3import "myapp/cmd"
4
5func main() {
6 cmd.Execute()
7}cmd/root.go
Define the root command as a package-level variable. Use is the command name, Short is the help text, and Run contains the logic. Execute() is the public entrypoint that parses args and runs the appropriate command.
1package cmd
2
3import (
4 "fmt"
5 "os"
6 "github.com/spf13/cobra"
7)
8
9var rootCmd = &cobra.Command{
10 Use: "myapp",
11 Short: "Short description",
12 Run: func(cmd *cobra.Command, args []string) {
13 fmt.Println("hello")
14 },
15}
16
17func Execute() {
18 if err := rootCmd.Execute(); err != nil {
19 os.Exit(1)
20 }
21}Adding a subcommand (cmd/serve.go)
Subcommands are defined similarly. Use init() to register flags and attach the subcommand to its parent. IntVarP binds the flag to a variable — the P variant adds a short flag (-p).
1package cmd
2
3import "github.com/spf13/cobra"
4
5var port int
6
7var serveCmd = &cobra.Command{
8 Use: "serve",
9 Short: "Start server",
10 Run: func(cmd *cobra.Command, args []string) {
11 // use port here
12 },
13}
14
15func init() {
16 serveCmd.Flags().IntVarP(&port, "port", "p", 8080, "port number")
17 rootCmd.AddCommand(serveCmd)
18}Usage
1myapp # runs root
2myapp serve -p 3000 # runs subcommand with flagKey concepts
Use— command nameShort/Long— help textRun— the actual logicFlags()— command-specific flagsPersistentFlags()— inherited by subcommandsArgs— positional argument validation (cobra.ExactArgs(1),cobra.MinimumNArgs(1), etc.)
Viper
Viper handles configuration from files, environment variables, and flags with a unified API.
Install
1go get -u github.com/spf13/viperBasic usage
Set defaults first, then tell Viper where to look for config files. AddConfigPath can be called multiple times to search multiple directories. Use typed getters to retrieve values.
1import "github.com/spf13/viper"
2
3func init() {
4 // Set defaults
5 viper.SetDefault("port", 8080)
6 viper.SetDefault("debug", false)
7
8 // Config file
9 viper.SetConfigName("config") // config.yaml, config.json, etc.
10 viper.SetConfigType("yaml") // explicit format
11 viper.AddConfigPath(".") // look in current dir
12 viper.AddConfigPath("$HOME/.myapp") // then home dir
13
14 if err := viper.ReadInConfig(); err != nil {
15 // handle missing config (often optional)
16 }
17}
18
19func main() {
20 port := viper.GetInt("port")
21 debug := viper.GetBool("debug")
22 name := viper.GetString("name")
23}Example config.yaml
Viper supports YAML, JSON, TOML, and other formats. Nested structures are supported.
1port: 3000
2debug: true
3name: myapp
4database:
5 host: localhost
6 port: 5432Nested keys
Access nested values using dot notation.
1viper.GetString("database.host") // "localhost"
Environment variables
AutomaticEnv makes Viper check for env vars matching config keys. SetEnvPrefix adds a prefix to avoid collisions. The replacer maps nested keys (dots) to underscores for env var names.
1viper.AutomaticEnv() // reads MYAPP_PORT, etc.
2viper.SetEnvPrefix("MYAPP") // prefix for env vars
3viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) // database.host → DATABASE_HOST
Cobra integration
Bind Cobra flags to Viper keys with BindPFlag. This unifies CLI flags, env vars, and config files under one key — Viper resolves them in priority order.
1var rootCmd = &cobra.Command{...}
2
3func init() {
4 rootCmd.Flags().IntP("port", "p", 8080, "port")
5 viper.BindPFlag("port", rootCmd.Flags().Lookup("port"))
6}Priority: flag > env > config > default
Unmarshal to struct
Map the entire config to a struct. Use mapstructure tags to match keys to fields.
1type Config struct {
2 Port int `mapstructure:"port"`
3 Debug bool `mapstructure:"debug"`
4 DB DBConfig `mapstructure:"database"`
5}
6
7var cfg Config
8viper.Unmarshal(&cfg)Watch for changes
Viper can watch the config file and trigger a callback on changes. Useful for live-reloading configuration.
1viper.WatchConfig()
2viper.OnConfigChange(func(e fsnotify.Event) {
3 fmt.Println("config changed:", e.Name)
4})