Why I Use Go for CLI Tools
Go's combination of fast compilation, single-binary output, and excellent standard library makes it the best language I've found for building CLI tools.
After building CLI tools in Python, Node.js, and Rust, I keep coming back to Go. Here's why.
Single binary distribution
When you compile a Go program, you get a single static binary with zero runtime dependencies. Your users don't need to install a runtime, manage virtual environments, or deal with DLL hell. They download a file, chmod +x, and run it.
GOOS=linux GOARCH=amd64 go build -o mytool-linux-amd64 .
GOOS=darwin GOARCH=arm64 go build -o mytool-darwin-arm64 .
That two-liner is your entire cross-compilation story. Compare this to Python, where you're fighting PyInstaller to get a bundled executable, or Node.js where pkg produces 50 MB blobs.
The standard library does most of what you need
Go ships with a remarkably complete standard library for CLI use cases:
flagfor argument parsing (or reach forcobra/urfave/clifor complex CLIs)os/execfor running subprocessesnet/httpfor talking to APIsencoding/jsonfor JSONtext/templatefor rendering output templatesosandfilepathfor filesystem operations
I can write a useful CLI without a single third-party dependency.
Fast compilation keeps the feedback loop tight
Go compiles quickly. A 10,000-line project builds in under a second. This matters during development — the delay between "save" and "can test this" is near-zero. Compare this to Rust, where incremental builds on a medium-sized project can take 10–30 seconds.
Goroutines make concurrent CLIs trivial
CLIs often need to do multiple things in parallel: check multiple APIs, scan files, process a queue. Go's goroutines make this straightforward without the callback hell of async JavaScript or the complexity of Python's asyncio.
var wg sync.WaitGroup
results := make(chan Result, len(items))
for _, item := range items {
wg.Add(1)
go func(i Item) {
defer wg.Done()
results <- process(i)
}(item)
}
wg.Wait()
close(results)
When I don't use Go
Go isn't always the right choice:
- Rapid prototyping: Python is faster to explore an idea
- Maximum performance + safety: Rust is worth the compile times
- Existing ecosystem: If your domain has great Python or Node libraries, use them
But for the majority of production CLI tools I've shipped, Go has been the right call. The combination of fast iteration, easy distribution, and a solid standard library is hard to beat.
What language do you reach for when building CLI tools? I'm curious if others have found a better fit.