Developer working on a laptop with code editor open, weighing backend language choices between Go and Rust

Rust vs Go for Backend Services in 2026

September 27, 2026 · 11 min read · By Jackson Harper

The Short Answer: Go Is Default, Rust Is Escape Hatch

Go remains the default language for backend services in 2026, while Rust is chosen for a narrower set of workloads where tail latency, memory footprint, and compile-time safety are strict requirements. This outcome results from the two languages’ runtime models rather than developer preference. Go enables a small team to deliver a concurrent service in days. Rust sacrifices that speed for predictable performance and a type system that prevents use-after-free and data-race bugs at compile time.

Most teams settle on roughly 80% Go and 20% Rust, reserving Rust for services that clearly fail their SLA. The rest of this article examines the specific data behind that split, including the sources of the figures and where they might be less definitive.

Choosing a backend language: Go as default, Rust as escape hatch

Key Takeaways

  • Go 1.26 shipped on February 10, 2026 with the Green Tea garbage collector enabled by default; the Go team reported many workloads spend about 10% less time in GC, with some seeing reductions up to 40%.
  • On CPU-bound benchmarks Rust’s Actix-web runs about 1.5x faster than Go’s Fiber, and Rust web servers typically use 2 to 4x less RAM.
  • Discord’s Read States service is the clearest Rust-wins case, but the same engineering post states the rest of Discord’s backend stayed on Go.
  • Rust exposes a smaller hiring pool and longer ramp-up (3 to 6 months to proficiency vs 2 to 4 weeks for Go), which is a real planning cost.
  • Go’s async model has no function coloring; Rust’s Tokio-based async is more powerful but carries Pin, lifetime, and cancellation-safety complexity.

Performance: Rust Wins CPU-Bound, Go Wins Enough

Rust runs faster on tight CPU-bound tasks. A 2026 comparison published by danilchenko.dev found Rust’s Actix-web runs about 1.5x faster than Go’s Fiber framework, using roughly 20% less memory. On a plaintext HTTP benchmark without a database, a Rust service on two CPU cores handled nearly 160,000 requests per second, while the comparable Go service reached about 105,000 RPS.

Rust vs Go performance: CPU-bound benchmarks

The difference shrinks quickly once a real workload is involved. Adding a Postgres round-trip and JSON serialization reduces the gap to roughly 15% to 30%. Most backend services spend most of their time on database, network, or serialization I/O rather than CPU. When that happens, the runtime stops being the bottleneck, and profiling usually points to a query or an N+1 call instead.

Latency-sensitive teams focus more on tail latency. Under a sustained load of 25,000 RPS, the same comparison measured Rust’s P99 latency at 310 ms versus Go’s 1,550 ms. The cause is Go’s garbage collector: individual pauses are short, typically under a millisecond on heaps below 4 GB, but under sustained concurrent load those pauses accumulate at the 99th percentile. Rust’s Tokio runtime uses work-stealing scheduling without a collector, so its tail latency remains more consistent.

One caution about benchmark interpretation: headline multipliers require careful examination. The often-cited “10x” figure from an AWS rewrite compared Kotlin on the JVM with Rust on a control plane that encountered JVM warm-up and GC limits, as explained in Werner Vogels’ account of Aurora DSQL work. That comparison does not involve Go versus Rust, and migrating a Go service will not reproduce that multiplier.

Concurrency: Goroutines vs Tokio

This is the most fundamental structural difference between the two languages. Go’s model is stackful and preemptive. Each goroutine has its own growable stack, the runtime can pause one goroutine to run another, and you write code that looks blocking while the scheduler runs it concurrently. There is no async keyword, no function coloring, and no cancellation-safety puzzles for typical cases.

Concurrency models: goroutines vs Tokio async runtime

Rust’s model is stackless and cooperative. An async fn returns a Future, and an executor, usually Tokio, drives it to completion. Function coloring means async propagates to every caller in the chain. Developers must learn Pin, lifetimes across .await, and cancellation safety through experience. What happens when a future is dropped during .await remains a topic of ongoing discussion, as detailed in the Cancelling async Rust write-up and Oxide RFD 400.

The trade-off goes both ways. Goroutines align with how most engineers already think about parallel work, and Go’s race detector catches data races during tests, covering much of the safety concern without type-system overhead. Rust’s async is more powerful when needed, but you pay for that control on every line that touches an async boundary, including lines where it does not matter. For a detailed explanation of how Rust enforces these guarantees at compile time, see our earlier analysis of the Rust compiler pipeline and borrow checker.

Memory: Where the 2 to 4x Gap Shows Up

Rust frees memory when ownership ends, so it has no background collector and no heap budget to tune. The trade-off is reasoning about lifetimes throughout the code. The benefit appears in cloud costs. Rust web servers typically use 50 to 80 MB of RAM for production workloads; comparable Go services use 100 to 320 MB.

At 12 replicas across three availability zones, that difference adds up quickly. A Go service using 250 MB across 36 pods consumes about 9 GB of cluster memory, while the Rust equivalent at 70 MB uses roughly 2.5 GB. Across 20 services in a microservice architecture, that can determine whether you need a three-node or five-node cluster.

Go’s garbage collector is less of a drawback than before. Go 1.26, released on February 10, 2026, enables the Green Tea garbage collector by default. In the Go team’s own write-up, many workloads spend around 10% less time in GC, with some seeing reductions up to 40%. Green Tea improves memory locality by scanning objects with vectorized operations. Note that these figures come from the Go team’s measurements, and the same post acknowledges some workloads do not benefit, which is why the team requested production feedback before making it the default.

Production Case Studies: Who Actually Switched

The strongest case for Rust on the backend comes from Discord. In a 2020 engineering post, Discord described its Read States service, which tracks which channels and messages each user has read. The service runs every time someone connects, sends, or reads a message, so it is on the critical path.

The Go version supported millions of users and tens of millions of read states in an in-memory LRU cache but showed latency and CPU spikes roughly every two minutes. Discord traced the cause to Go runtime behavior: the collector runs at least every two minutes regardless of heap growth, and each run scanned the entire cache. Shrinking the cache reduced spikes but increased P99 latency, because a smaller cache caused more database loads. Rust removed the collector and eliminated the spikes.

Discord’s engineers were clear about the limits of that story in the same post. It was one service running at extreme scale; the rest of Discord’s backend stayed on Go, and the post states plainly that “Go served us well.” Teams running CRUD APIs and microservices will not see a similar benefit.

Another example is Cloudflare’s Pingora, a Rust async framework for building proxies. Cloudflare’s open-sourcing announcement states that Pingora has handled nearly one quadrillion internet requests across its global network, and the company credits its multi-threaded architecture with saving CPU and memory. That is a systems-layer workload, exactly where Rust’s trade-offs pay off.

Ecosystem, Build, and Deploy Ergonomics

Go dominates cloud-native infrastructure. Kubernetes, Docker, Terraform, Prometheus, Istio, and Helm are all written in Go, along with most cloud provider SDKs. If your service runs on Kubernetes and communicates with neighbors over gRPC or REST, the toolchain, deployment model, and debugging tools all assume Go. The CNCF’s 2026 Annual Survey reported that 82% of container users run Kubernetes in production, which reflects how much backend work happens within that environment.

Rust’s async web stack is mature but narrower. Tokio is the standard runtime, with Axum and Actix built on top, and the ecosystem centers around serde for serialization and reqwest for HTTP clients. For a detailed look at how that runtime developed, see our earlier piece on why Tokio still dominates async Rust. Coverage of cloud-provider SDKs is less extensive than Go’s, which adds cost when a service must integrate with a niche managed product.

Build times impose Rust’s steepest everyday cost. Go compiles in seconds with sub-second incremental builds, while Rust generally takes 15 to 30 seconds for a clean build and longer on CI, as the same comparison notes. Go also cross-compiles easily with the GOOS/GOARCH environment variables, while Rust requires a target triple plus linker configuration. Both produce a single binary with no runtime dependency, so deployment is similar once the build completes.

Hiring and Compensation

Go has a substantially larger talent pool. As of mid-2026 there were roughly 5 to 7 times more open positions mentioning Go than Rust on major job boards, according to the same danilchenko.dev analysis. A startup needing to fill three backend roles by the end of the quarter will fill them faster with Go, and the interview process tends to focus on goroutines, channels, and interface design rather than lifetime and async-pinning challenges.

Rust roles pay more, but due to scarcity rather than intrinsic value. Reported US medians range roughly from $135K to $175K for Go and $145K to $185K for Rust, with senior ranges of $160K to $200K and $185K to $230K respectively in the same dataset. Employers hiring Rust tend to be fintech, infrastructure, and security teams paying top market rates for a small candidate pool. None of these figures come from a single canonical source; treat them as approximate ranges rather than exact benchmarks.

Go vs Rust at a Glance

Dimension Go Rust
Plaintext HTTP throughput (2 cores) ~105,000 RPS ~160,000 RPS (Actix-web)
P99 latency under 25,000 RPS load 1,550 ms 310 ms
Typical production RAM per service 100 to 320 MB 50 to 80 MB
Clean build time Seconds (sub-second incremental) 15 to 30 seconds, longer on CI
Time to proficiency 2 to 4 weeks 3 to 6 months
Reported US median salary $135K to $175K $145K to $185K
Senior salary range $160K to $200K $185K to $230K

The Migration Question

Rewriting a working service in another language is the most expensive option and should be a last resort. The common approach is to keep the existing Go service and extract only the hot path causing measurable issues. That is effectively what Discord did: it did not rewrite its entire backend, only one service whose GC behavior violated its product requirements.

Rust also interoperates with existing systems through the C ABI, so a Rust library can be called from a Go service via cgo. That approach has its own cost. Baseline cgo call overhead dropped by roughly 30% in recent Go releases according to the Go 1.26 release notes, but crossing the boundary still adds overhead and complicates the build. For most teams, a full service boundary (meaning a separate Rust service behind a network call) is easier to manage than an in-process FFI boundary.

If you are starting a Go service from scratch, concurrency primitives matter more than the language choice. Our guide to Go concurrency basics and patterns covers the goroutine, channel, and context patterns that distinguish a service that scales from one that deadlocks under load.

Outlook and Falsifiable Call

The 80/20 split that held through 2025 and 2026 appears likely to continue for the next year. Go’s collector improvements keep expanding the range of workloads it handles comfortably, and each release removes cases that once justified a Rust rewrite. Green Tea’s default activation in Go 1.26 is the clearest example: the GC-overhead reduction the Go team measured matches the pressure that pushed teams like Discord toward Rust.

At the same time, Rust’s async web stack continues to mature, and migration costs remain high enough that most teams will switch only when a specific service clearly fails its SLA. That makes Rust an escape hatch rather than a default choice. Teams most likely to adopt it first have strict P99 latency targets, tight memory budgets at the edge, or security-critical code where memory-safety guarantees are mandatory.

Here is a prediction I am willing to be held to. Go will remain the higher-volume backend hiring language, with at least 4 times more open backend postings than Rust on major job boards by March 31, 2027. The reasoning is that Go’s 2-to-4-week proficiency curve and its standardized cloud-native library make it the easiest path for CRUD, control-plane, and microservice teams, and hiring follows the installed base.

I also expect that by June 30, 2027, at least one major cloud provider will deploy a production service written in Rust that replaces a Go service on a latency-sensitive path, publishing measured tail-latency improvements. The Discord Read States case and Pingora’s growth have established Rust as the standard solution for collector-induced P99 spikes, and the economics of that fix are well documented enough to be repeated.

Decision Framework

Choose Go when the service is I/O-bound, such as an API gateway, CRUD service, or webhook processor; when the team has mixed experience levels; when you must ship in weeks; or when you need to hire backend engineers within six months. That covers most backend work.

Choose Rust when the service is CPU-bound or latency-sensitive, such as a proxy, codec, or database engine; when memory is genuinely constrained at the edge; when P99 targets are below single-digit milliseconds; or when memory-safety guarantees are mandatory for security reasons. If none of those apply, Go is almost always the faster path to a working, maintainable system.

Sources and References

Sources cited while researching and writing this article:

Jackson Harper

Runs on caffeine, market data, and an unreasonable number of parameters. Never sleeps. Posts daily recaps before sunrise and swears he's read every earnings report ever filed.