In Part 1 I covered why Rust on AWS Lambda is worth exploring and laid out the project setup. This post measures the one number that matters most for serverless latency: cold start time. To get a clean floor measurement, I used the simplest possible endpoint with no database, no external calls, and no middleware.
The Benchmark Setup
The handler is a single health endpoint built with Axum and Cargo Lambda:
use axum::Router;
use axum::http::StatusCode;
use axum::routing::get;
use lambda_http::{Error, run};
#[tokio::main]
async fn main() -> Result<(), Error> {
run(Router::new().route("/health", get((StatusCode::OK, "Healthy".to_string())))).await
}
The release profile is tuned for a small, fast binary:
[package]
name = "fulgurion-lambda"
version = "0.1.0"
edition = "2024"
[dependencies]
lambda_http = { version = "1" }
axum = { version = "0.8", features = ["macros"] }
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
strip = true
The lto, codegen-units, and strip flags matter here. Link-time optimization and single codegen unit produce a smaller, tighter binary. Stripping debug symbols removes anything the Lambda runtime does not need. The result, cross-compiled for Lambda’s ARM64 runtime:
cargo lambda build --compiler cross --release --arm64
Uploaded package size: 885.7 kB.
The Results
I used oha to fire 5 parallel requests, forcing 5 simultaneous cold starts:
oha -n 5 -c 5 https://redacted.execute-api.us-east-1.amazonaws.com/health
Lambda’s structured log for each invocation:
REPORT RequestId: e85978b8-96f3-4a0e-9511-c22672da4f02 Duration: 1.44 ms Billed Duration: 20 ms Memory Size: 512 MB Max Memory Used: 16 MB Init Duration: 18.45 ms
REPORT RequestId: a6953d6e-d437-466a-9273-480faf5db2dc Duration: 1.49 ms Billed Duration: 21 ms Memory Size: 512 MB Max Memory Used: 16 MB Init Duration: 18.91 ms
REPORT RequestId: 7e151036-c109-405d-a9ba-2f81b0f7a1e1 Duration: 1.75 ms Billed Duration: 25 ms Memory Size: 512 MB Max Memory Used: 16 MB Init Duration: 22.43 ms
REPORT RequestId: 19ed8d7f-85fe-4c80-a530-7b44f429a8d5 Duration: 1.93 ms Billed Duration: 25 ms Memory Size: 512 MB Max Memory Used: 16 MB Init Duration: 22.24 ms
REPORT RequestId: c4fa04e9-d361-4fe4-9a09-cbaf67f57f29 Duration: 1.63 ms Billed Duration: 22 ms Memory Size: 512 MB Max Memory Used: 16 MB Init Duration: 19.43 ms
Init duration ranges from 18 to 22 ms. Handler invocation stays under 2 ms. Memory usage peaks at 16 MB across all five environments.
What Cold Start Means Here
A cold start happens when Lambda has no warm execution environment to reuse and must provision one from scratch before running your handler. The Init Duration field in the logs above is the cost of that provisioning. AWS bills for it on top of the handler duration.
For a warm invocation the cost is ~1.5 ms. A cold start adds ~20 ms of init on top of that. For a user-facing endpoint, that difference is perceptible.
How These Numbers Compare
These results line up with the broader landscape. lambda-perf by Maxday benchmarks cold start P50 and P99 across languages, memory tiers, and CPU architectures. Rust consistently sits at the low end alongside Go and C++, well below JVM or interpreted runtimes.
The 16 MB memory footprint is also worth noting. Lambda pricing is based on GB-seconds, so a Rust function at 16 MB and 1.5 ms of handler duration costs a fraction of what an equivalent Node or Python function would, before even accounting for cold starts.
When Cold Starts Become a Problem
The numbers above are favorable, but cold starts can still hurt depending on your traffic pattern:
- Bursty or infrequent traffic. Lambda shuts down idle execution environments. Long gaps between requests mean the next request pays the cold start cost.
- Sudden concurrency spikes. Each concurrent in-flight request needs its own execution environment. A burst of simultaneous requests will trigger multiple cold starts at once.
- Frequent deployments. A new deployment invalidates existing environments, forcing cold starts on the next wave of traffic.
Conclusion
For a minimal Rust Lambda, cold start lands between 18 and 22 ms with an 885.7 kB binary and 16 MB of memory. That is a strong baseline. The next post will break down what happens inside Lambda during that init window, and why each phase matters for Rust specifically.
Links
- oha: HTTP load testing tool used to force parallel cold starts
- lambda-perf by maxday: community benchmark comparing cold start P50/P99 across languages, memory tiers, and CPU architectures
- AWS Lambda billing for init phase: AWS announcement explaining that the init phase is billed as part of invocation duration
- Understanding and Remediating Cold Starts: AWS deep dive on cold start causes and mitigation strategies
- AWS Lambda custom runtimes: official docs on the OS-only runtime used by Rust on Lambda
- Benjamen Pyle: Rust on AWS Lambda (QCon 2025): the talk that started this series