Measured benchmark · September 2026

Spring Boot on Fargate vs.
Quarkus native on Lambda

The same application, deployed two ways on AWS, load-tested identically. Run 8 to 9 September 2026 in us-east-1.

Every number below comes from a raw k6 summary or CloudWatch pull kept from that run. Where a figure is modeled rather than measured, it says so.

Summary

Spring Boot on FargateQuarkus native on LambdaChange
Cold start54.50 s684 ms80x faster
Median latency92.85 ms26.55 ms3.5x faster
p99 latency218.25 ms50.16 ms4.4x faster
Worst case1,895.89 ms235.08 ms8.1x tighter
Throughput33.24 req/s37.79 req/s+13.7%
Memory in use~340 MB166 MB peak~2x lower
Server-side errors00even

The serverless rebuild was faster at every percentile, not only in the tail, and it did that while carrying TLS overhead the Fargate deployment was not paying.

Method

The application. Spring PetClinic REST. The Fargate deployment runs it as a single Spring Boot service. The Lambda deployment is the same application split into seven Quarkus modules, each compiled to a GraalVM native image and deployed as its own function behind its own API Gateway HTTP API.

The infrastructure. Both stacks ran in the same AWS account and region against the same PostgreSQL database. Fargate: 2 tasks at 0.5 vCPU and 1 GB each, behind an Application Load Balancer, connecting to RDS directly. Lambda: 1024 MB per function on arm64, connecting through RDS Proxy, which is the AWS-recommended pattern because bursty Lambda concurrency can otherwise exhaust Postgres connections.

The load test. k6, 20 virtual users, 5 minutes, constant VUs. Both scripts are identical in structure: the same weighted endpoint mix (owners 40%, pets 25%, vets 15%, visits 10%, pettypes 5%, specialties 5%) and the same 0.5 s sleep between iterations. The only difference is that the Lambda script targets seven API Gateway URLs where the Fargate script targets one base URL, which is inherent to the architectures rather than a change in test design.

One asymmetry, disclosed because it matters

The Fargate run shows TLS handshake time at zero throughout, meaning it served plain HTTP through the ALB. The Lambda run went over HTTPS through API Gateway, paying up to 76.9 ms of handshake. Lambda is carrying encryption overhead that Fargate is not, and still wins every latency measure below. Correcting this asymmetry would widen the gap, not narrow it.

Cold start

The largest single difference, and the one that decides whether serverless is viable for a given workload at all.

Spring Boot on Fargate
54.50 s

Two independent tasks at 54.806 s and 54.192 s, read from the application's own startup log line via CloudWatch Logs Insights. Reproducible across both tasks, not a one-off.

Quarkus native on Lambda
684 ms

Averaged across 23 recorded cold starts spanning deployment and both load tests, taken from the init duration on CloudWatch report lines.

FunctionCold startsAvg initMinMax
visits3600.48 ms483.05 ms664.33 ms
pettypes3649.82 ms492.44 ms751.91 ms
vets4664.80 ms573.88 ms719.32 ms
owners6690.64 ms662.62 ms726.09 ms
pets5703.38 ms681.02 ms768.30 ms
specialties2826.03 ms707.76 ms944.30 ms

The honest caveat

54.5 s is specific to a cost-optimized 0.5 vCPU task. JVM startup is CPU-bound, and these logs show it: parsing logback.xml alone took 1,090 ms, which is evidence of real CPU throttling at this task size. A larger Fargate task would start meaningfully faster. The 80x figure is accurate for this configuration and should not be read as the number for every Spring Boot deployment.

Latency under load

Two Quarkus runs were retained and both are shown. Earlier runs from the same session were not kept, so only these two are cited.

PercentileFargateLambda run 4Lambda run 5
min79.43 ms14.89 ms14.69 ms
median92.85 ms26.55 ms26.63 ms
average99.71 ms27.63 ms29.42 ms
p90103.09 ms33.98 ms35.20 ms
p95120.77 ms36.92 ms38.87 ms
p99218.25 ms50.16 ms55.04 ms
max1,895.89 ms235.08 ms1,646.67 ms
requests9,98911,35811,316
throughput33.24/s37.79/s37.66/s

Run 5's outlier is real and is not hidden. One request took 1,646.67 ms, almost certainly a cold start caught mid-test. Run 4's worst case was 235 ms. The two runs agree closely everywhere else, including the median to within 0.08 ms, so the maximum is the only materially unstable figure between them. Any serverless deployment shows this shape: an excellent warm distribution with occasional cold-start spikes in the tail.

Why Lambda wins the median too. The intuition that an extra API Gateway hop must cost latency is correct in isolation, but it is outweighed here. Measured at the function, Lambda's own execution averaged 12.84 ms. The rest of the 26.55 ms the client observed is API Gateway, TLS and network. The Fargate side is spending its 92.85 ms inside a thread-pooled JVM on a throttled half-vCPU, and that dominates.

Reliability

Fargate: 9,989 requests, zero failures. Lambda: 11,358 requests with 4 client-side failures in run 4 and 11,316 with 30 in run 5. Those were not Lambda errors. CloudWatch reports zero errors for all six functions across 8,466 recorded invocations. The failures k6 saw were client-side, the expected consequence of the Lambda client opening connections to six separate TLS endpoints where the Fargate client used one load balancer. That is a property of the test topology, not of the platform.

FunctionInvocationsAvg durationMax durationErrorsPeak concurrency
owners3,47711.31 ms845.81 ms07
pets2,04718.95 ms789.28 ms05
vets1,27811.41 ms790.36 ms04
visits81511.49 ms724.16 ms03
pettypes4427.58 ms773.34 ms02
specialties4078.16 ms769.14 ms02
Total8,46612.84 ms0

Memory

Fargate held 29.9% to 33.8% of a 1 GB task across the test window, roughly 306 to 346 MB, with CPU averaging 8.4% to 22.7% and spiking to 80.5%. Lambda peaked at 166 MB of 1024 MB allocated, on the busiest function. A single comparative percentage would mislead here, because one always-on provisioned task is not the same unit as seven functions billed on what they actually consume, so both are given as measured.

FunctionPeakAverageInvocations
owners166 MB154.64 MB3,826
pets162 MB151.15 MB2,338
visits160 MB141.06 MB937
vets159 MB142.90 MB1,421
specialties148 MB132.07 MB476
pettypes147 MB128.85 MB410

Cost

These figures are modeled, not billed. They apply published us-east-1 on-demand pricing to the resource shapes measured above. Excluded from both sides: the database, CloudWatch Logs and data transfer, since both architectures need them at comparable rates and they do not change the delta. Lambda's always-free tier is not applied, so the low tier is an upper bound.

The original model assumed 150 ms average Lambda execution. The measured average is 12.84 ms, so that assumption was 11.7x too high. Both versions are shown.

Requests/monthFargate + ALBLambda, 150 ms assumedLambda, 12.84 ms measured
100,000~$55~$0.32~$0.14
5,000,000~$72~$16~$6.86
50,000,000~$190~$160~$68.56

Fargate at 50M assumes scaling from 2 tasks to 4. That scaling is modeled, not measured: we did not load-test Fargate at these volumes, so there is no measured break-even point. Up to 50M a month, Lambda is cheaper in every tier.

Where the money actually goes

At measured duration, Lambda compute is only $0.17 per million requests. API Gateway is $1.00 per million, which is 73% of the total. Past a few million requests a month, the thing worth optimizing is not the compute, it is the gateway. Lambda Function URLs or an ALB in front of Lambda would cut most of it.

PetClinic is a demo app. For the same comparison on a production SaaS API, with the Lambda side measured under load in eu-central-1, see what a real SaaS API costs on Fargate vs. Lambda.

What this does not prove

  • It is one reference application. PetClinic is a small CRUD API. Something with heavier per-request work, large in-memory caches, or long-held connections may behave differently.
  • Two retained Lambda runs against one Fargate run. Enough to establish the shape, not enough to characterize run-to-run variance precisely.
  • Nothing here measures developer experience, operational burden, or the cost of the migration itself, which are usually what actually decides the question.

Want this run against your application?

The tooling that produced every number here deploys both stacks, load-tests each, collects the CloudWatch metrics, and tears everything down. Every migration we take on ships with a benchmark like this one, measured on your code rather than ours.

Book a free assessment