Advanced Guide
Building CLI Applications
GoFr provides a simple way to build command-line applications using gofr.NewCMD(). This creates standalone CLI tools without starting an HTTP server.
Configuration
To configure logging for CLI applications, set the following environment variable:
CMD_LOGS_FILE: The file path where CLI logs will be written. If not set, logs are discarded.
Getting Started
Create a basic CLI application with subcommands:
package main
import (
"fmt"
"gofr.dev/pkg/gofr"
)
func main() {
app := gofr.NewCMD()
// Simple hello command
app.SubCommand("hello", func(c *gofr.Context) (any, error) {
return "Hello World!", nil
}, gofr.AddDescription("Print hello message"))
// Command with parameters
app.SubCommand("greet", func(c *gofr.Context) (any, error) {
name := c.Param("name")
if name == "" {
name = "World"
}
return fmt.Sprintf("Hello, %s!", name), nil
})
app.Run()
}
Key GoFr CLI Methods
gofr.NewCMD(): Initialize a CLI applicationapp.SubCommand(name, handler, options...): Add a subcommandgofr.AddDescription(desc): Add help descriptiongofr.AddHelp(help): Add detailed help textctx.Param(name): Get command parametersctx.Out.Println(): Print to stdoutctx.Logger: Access logging
Running CLI Applications
Build and run your CLI:
go build -o mycli
./mycli hello
./mycli greet --name John
./mycli --help
Example Commands
# Basic command
./mycli hello
# Output: Hello World!
# Command with parameter
./mycli greet --name Alice
# Output: Hello, Alice!
# Help
./mycli --help
Exit Codes
Scripts and CI read the exit status of a CLI application to tell whether it succeeded:
| Outcome | Exit code |
|---|---|
The handler returns a nil error | 0 |
| The handler returns a non-nil error (its data, if any, is still printed) | 1 |
| The subcommand is missing or not registered | 1 |
help as a bare word (it is not a help flag; only -h / --help are) | 1 |
The subcommand is registered with a nil handler | 1 |
-h / --help on its own or after a registered subcommand that has a handler | 0 |
The error is written to stderr before the process exits. A missing or unregistered subcommand (including a bare help) also prints the list of available commands to stdout; a subcommand registered with a nil handler prints only the error. When a command fails, GoFr flushes telemetry and closes the logger, then calls os.Exit(1). Because of that, functions deferred in your main() (for example defer db.Close()) do not run when a command fails. Put cleanup that must always happen inside the handler rather than in a defer in main().
For more details, see the sample-cmd example.