After writing CLI tools in both Rust and Go over the last few years, here are the things that actually matter when choosing between them.
Startup time
Go wins. A trivial Go program starts in ~1-5ms. A trivial Rust program also starts in ~1-5ms. Both are negligible for CLI tools. (The old argument about Go’s startup was mostly about JVM-vs-Go, not Go-vs-Rust.)
Binary size
Out of the box:
- Go: 5-15 MB for a small program
- Rust: 2-8 MB for a small program (with LTO and strip)
After aggressive optimization:
- Go with upx: 2-5 MB
- Rust with upx + panic=abort: 500 KB - 2 MB
Rust wins if binary size matters, but it matters less than people think.
Library ecosystem
Go: vast stdlib covers most needs. HTTP, JSON, crypto, file operations all built-in. Third-party libraries have varying quality.
Rust: smaller stdlib, larger third-party ecosystem (crates.io). Quality is generally very high. But you’re pulling in more dependencies.
For a simple CLI that reads a file, parses JSON, and makes HTTP requests:
- Go: 0 external dependencies possible
- Rust: typically 5-20 crates (tokio, serde, serde_json, reqwest, clap)
Compilation speed
Go wins decisively. A medium Go project compiles in seconds. A medium Rust project can take minutes.
This affects development flow. Fast iteration loops matter.
Runtime performance
For typical CLI workloads (read file, process, write), both are plenty fast. Rust has the edge when:
- Doing CPU-intensive work (parsing, crypto, compression)
- Memory-constrained environments
- Need for predictable latency (no GC pauses)
Go is fine for:
- Network-heavy tools
- Anything where the bottleneck is I/O or external APIs
- Most sysadmin tooling
Error handling
Go: explicit if err != nil everywhere. Verbose but straightforward.
Rust: ? operator with Result types. More concise, forces you to handle errors at compile time.
Rust’s error handling is better but has a steeper learning curve. The anyhow and thiserror crates make it more ergonomic.
Memory safety
Rust prevents entire classes of bugs (use-after-free, data races, null pointer derefs) at compile time. Go uses garbage collection + runtime panics for similar issues.
For security-sensitive tools, Rust is clearly better. For most CLI tools, either is fine.
Cross-compilation
Both are excellent:
- Go:
GOOS=windows GOARCH=amd64 go build— just works - Rust:
cargo build --target x86_64-pc-windows-gnu— needs target toolchain installed
Go has smoother cross-compilation experience.
My personal heuristic
Use Go when:
- The tool is network-heavy or API-driven
- Rapid prototyping matters
- You want minimal dependencies
- Linking will target existing Go codebases
Use Rust when:
- Performance or memory efficiency is critical
- The tool is parsing-heavy or compute-heavy
- You need a rock-solid binary for production
- You’re willing to pay upfront learning cost for long-term benefits
For sysadmin tools I reach for Go 80% of the time. For specialized tools that need to be reliable and fast, Rust.
What you don’t choose between them over
- “Performance” — both are fast enough for anything you’d write as a CLI
- “Modern language features” — both have what you need
- “Community” — both are mature and active
Choose based on your specific context: team knowledge, existing codebases, performance needs, iteration speed.