Building CLI Tools with Go
How to create fast, cross-platform command-line tools using Go's standard library.
goclitools

Go is my go-to for CLI tools. Single binary output, easy cross-compilation, and a great standard library make it perfect for the job.
A Simple Example
Let's build a file counter:
go
package main
import (
"flag"
"fmt"
"os"
"path/filepath"
)
func main() {
dir := flag.String("dir", ".", "directory to scan")
ext := flag.String("ext", "", "filter by extension")
flag.Parse()
count := 0
filepath.Walk(*dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
if *ext == "" || filepath.Ext(path) == *ext {
count++
}
}
return nil
})
fmt.Printf("Found %d files\n", count)
}Usage:
bash
./filecount -dir ./src -ext .goAdding Color
The fatih/color package makes terminal output nicer:
go
package main
import (
"fmt"
"github.com/fatih/color"
)
func main() {
green := color.New(color.FgGreen, color.Bold).SprintFunc()
yellow := color.New(color.FgYellow).SprintFunc()
fmt.Println(green("✓ Success"))
fmt.Println(yellow("⚠ Warning"))
}Interactive Input
go
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func confirm(prompt string) bool {
reader := bufio.NewReader(os.Stdin)
fmt.Printf("%s [y/N]: ", prompt)
input, _ := reader.ReadString('\n')
input = strings.ToLower(strings.TrimSpace(input))
return input == "y" || input == "yes"
}
func main() {
if confirm("Continue?") {
fmt.Println("Proceeding...")
}
}Cross-Compilation
Build for any platform with environment variables:
bash
# Linux
GOOS=linux GOARCH=amd64 go build -o app-linux
# macOS (Apple Silicon)
GOOS=darwin GOARCH=arm64 go build -o app-mac
# Windows
GOOS=windows GOARCH=amd64 go build -o app.exeNo Docker, no VMs. Just works.
Go's simplicity is its strength. No runtime dependencies, no package managers on the user's machine—just ship a binary.