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.