Hi! In this post I compare Node.js and Rust on Google Cloud Run to see which one is faster.
You could argue that most of a request's time is spent on I/O, so the language shouldn't matter much. That's a fair point, so I built the most I/O-bound service I could think of. Each API does exactly one thing: connect to Redis, read a string, and return it as JSON. The only I/O is the Redis call, and there is no other business logic.
The payload is a random JSON document of exactly 100 KB (102,400 bytes). The size was an arbitrary choice: big enough to make serialization and network copies matter, small enough to be realistic.
Everything is open source, so you can reproduce it: andersondanilo/cloudrun-benchmark.
The setup
Both APIs expose a single endpoint, GET /data, which returns the JSON stored under one Redis key. Everything runs in the same region (São Paulo, southamerica-east1), and the infrastructure is created with Pulumi.
| Component | Details |
|---|---|
| Node.js service | Cloud Run, Node.js 22 (Alpine), Fastify 5, ioredis |
| Rust service | Cloud Run, Rust, Poem 3 (tokio), redis-rs, distroless image |
| Cloud Run config (both) | 1 vCPU, 512 MiB, exactly 1 instance (min = max = 1), concurrency 20, southamerica-east1
|
| Redis |
e2-micro VM, Debian 12, redis-server with password, maxmemory 512mb, persistence off, same zone as the services, reached over its internal IP via Direct VPC egress |
| Load generator |
e2-micro VM, Debian 12, same zone, wrk
|
| wrk parameters | 2 threads, 20 connections (matches the Cloud Run concurrency), 5 s warm-up, then a 30 s measured run |
| Payload | Random JSON, exactly 102,400 bytes |
Running a single instance per service keeps the comparison fair: both get the same CPU and memory, and neither can scale out to hide its limits.
Results
| Node.js (Fastify) | Rust (Poem) | |
|---|---|---|
| Requests/sec | 237.72 | 467.93 |
| Transfer/sec | 23.26 MB | 45.79 MB |
| Latency (avg) | 83.80 ms | 42.59 ms |
| Latency p50 | 81.34 ms | 42.16 ms |
| Latency p90 | 95.26 ms | 48.79 ms |
| Latency p99 | 112.70 ms | 58.97 ms |
| Requests in 30 s | 7,139 | 14,051 |
Rust reached about double the requests per second (1.97x) with about half the latency at every percentile. With a fixed number of connections the two numbers are linked: 20 connections at roughly 84 ms per request is about 238 requests per second, and 20 connections at roughly 43 ms is about 468.
Caveats
- This is one test on one machine setup, so treat the numbers as a comparison between these two stacks, not as a universal verdict on Node.js vs Rust.
- Both VMs are
e2-micro, which is a shared-core machine type. The Redis VM or the load generator may be limiting the results, especially for Rust. I didn't test whether a bigger load generator or Redis VM pushes Rust further. - Each service ran on a single Cloud Run instance with 1 vCPU. With more instances, both would scale out, and the gap per instance is what would matter for cost.
Conclusion
Even for a service that only reads a string from Redis and returns it, the runtime made a clear difference: Rust served twice the traffic at half the latency on the same Cloud Run configuration. My guess is that handling a 100 KB payload on every request (reading it from Redis and writing it to the socket) costs more CPU than it seems, but I didn't profile it, so that part is a hypothesis.
If you want to run it yourself, the repo has everything: both APIs, the Pulumi infrastructure, and the benchmark script.
Top comments (0)