Back in 2023, I conducted a comprehensive concurrency evaluation comparing six different programming languages in AWS Lambda. Two years later, I decided to give it another go to see what effect a better-architected solution, new language versions, and code optimizations would provide.
The benchmark remains the same: implement concurrent S3 object processing in AWS Lambda using language-specific idioms. Each implementation must list up to 1000 objects from an S3 bucket, fetch their contents concurrently, and optionally search for a specific string. The following pseudo code showcases the general idea for the target implementation:
# Concurrency evaluation pseudo-code example
func handler(event):
timer.start()
result = processor(event)
timer.stop()
return {
"time": timer.elapsed,
"result": result
}
func processor(event):
s3_objects = aws_sdk.list_objects(s3_bucket)
results = [get(s3_key, event[find]) for s3_objects]
return first_non_none(results) if event[find] else str(len(s3_objects))
func get(s3_key, find):
body = aws_sdk.get_object(s3_key).body
return body.find(find) if find else None
The goal is to measure how effectively each language handles I/O-bound parallel workloads in a serverless environment. The exact same set of files from the 2023 benchmark was used to ensure fair comparison.
This article explores what has changed in two years and how these improvements impact real-world serverless performance. The results reveal some surprising findings about infrastructure changes, language runtime evolution, and the effectiveness of code optimizations.
What’s Changed Since 2023?
Rather than revolutionary changes, the improvements can be divided into three categories: better architecture decisions, updated runtimes, and more carefully optimized implementations.
Private VPC Connectivity to S3
The most significant architectural change is the shift to private VPC connectivity. In the 2023 evaluation, Lambda functions accessed S3 over the public internet. This time, all Lambda functions are deployed within a VPC and access S3 exclusively through VPC endpoints, avoiding the public internet. Routing through VPC endpoints eliminates additional network hops and provides more predictable performance characteristics.
S3 Express One Zone
This evaluation leverages S3 Express One Zone, AWS’s high-performance storage class introduced in November 2023. AWS claims it delivers up to 10x better performance than S3 Standard, handling hundreds of thousands of requests per second with consistent single-digit millisecond latency. For data-intensive serverless applications, the promise sounds appealing. The question is whether these theoretical improvements translate to measurable gains in our concurrent Lambda workload.
Upgraded Language Versions and Runtimes
Over two years, there has been evolutionary progress in each language’s development. In this benchmark, we use the language-specific Lambda runtime when available.

Lambda Runtime Configuration: 2023 vs. 2025
Beyond runtime upgrades, here’s a list of language-specific changes implemented for this benchmark:
- Python: No significant code changes.
- Node.js: No significant code changes.
- Go: With AWS dropping the native Go runtime, Go now uses
provided.al2
and migrated from Intel to ARM architecture. Code optimization focused on ensuring better low-memory performance. - Rust: Code improvements to more closely follow the implementation guidelines and eliminate unnecessary logic.
- Java: Now using
virtual threads
on Java 21. Additional code improvements ensure closer adherence to implementation guidelines. - C++: Significant code improvements to follow implementation guidelines more closely and avoid unnecessary logic. Compilation optimizations leverage modern C++23 features and GCC improvements for better performance.
Understanding Lambda Memory Configuration and Pricing
Before diving into results, it’s important to understand how Lambda’s memory configuration works. When you allocate memory to a Lambda function, you’re not just getting RAM — you’re also getting proportional CPU power and additional vCPUs at certain thresholds.

AWS Lambda Pricing vs. Memory Configuration
This chart shows the relationship between memory allocation, pricing, and available vCPUs. The vCPU counts were determined by running a Python Lambda function at different memory configurations and querying os.cpu_count(). Notice the step function in pricing and the discrete jumps in vCPU availability.
While Python and Node.js are restricted to a single thread (unable to leverage multiple vCPUs), languages like Go, Rust, Java, and C++ can use all available vCPUs for parallel processing. Lambda scales compute proportionally based on memory configuration. If this scaling were linear (which we don’t know), configuring memory just below each price threshold would maximize value. For instance, configuring 511MB should yield performance nearly identical to 512MB, yet cost only as much as 128MB — effectively a 75% discount.
Following the 2023 approach, we’ve selected memory configurations at these key price points, just before each increase (marked in the chart), to identify cost-performance sweet spots.
Architecture Change Impacts
First, let’s compare the impact of architectural changes on performance.
Public vs. Private S3 Connectivity Comparison
This comparison measures the impact of network architecture using concurrent Python code (511MB memory configuration). The 2023 results show performance when S3 is accessed from the internet, while 2025 results use a private VPC endpoint to access S3.

Public vs. Private S3 Connectivity Comparison: 2023 vs. 2025
Comparing these charts reveals our first surprise: there’s no warm-up effect. In 2023, we observed S3 gradually ramping up capacity to handle our requests, with response times improving over the first several requests. In 2025, response times are immediately faster from the first request.
I retested with the 2023 version to confirm whether the warm-up effect still existed when accessing S3 over the public internet. It did. This suggests that accessing S3 through VPC endpoints provides immediate full capacity, eliminating the gradual ramp-up period.
Standard S3 vs. S3 Express One Zone

S3 General Bucket vs. S3 Directory Bucket
Our second surprise: S3 Express One Zone shows no measurable advantage over Standard S3 in this benchmark. Our simple workload likely doesn’t reveal the benefits AWS claims for real data-intensive and high-throughput scenarios.
Performance Across All Languages: Consistent Improvement

Benchmark Comparison: 2023 vs. 2025
The side-by-side comparison shows how each language now performs consistently across all memory configurations. For each language and Lambda memory configuration, the benchmark was executed three times, and the average duration was then used.
Performance Improvements Across All Languages
Every language shows significantly better performance in 2025. The combination of runtime upgrades, architectural improvements, and code optimizations has benefitted all implementations.
The improvements are particularly dramatic at lower memory configurations. In 2023, several languages struggled below 512MB. In 2025, all languages perform smoothly even at 128MB, the minimum Lambda memory allocation.
The 128MB Breakthrough
All languages now successfully complete the benchmark at the minimum 128MB memory configuration. In 2023, several implementations struggled or failed at this level. This improvement comes primarily from more careful code optimization — with one notable exception: Java’s virtual threads are the only major language feature change that significantly impacts performance.
A Closer Look at Memory Configuration Performance
While the overall improvements are impressive, we still want to see differences between the languages.

Benchmark Comparison Lower Memory Configurations: 2023 vs. 2025
In 2023, several languages either failed or performed poorly at 128MB.
In 2025, all languages finished successfully across all low-memory configurations. The curves are smooth and predictable.While it’s encouraging that all languages now execute successfully at 128MB, this memory configuration still isn’t sufficient for any language to achieve optimal performance.

Benchmark Comparison Higher Memory Configurations: 2023 vs. 2025
At higher memory configurations, the improvements aren’t as dramatic. Only Java shows some significant improvements, while for others we see only diminishing returns. We can assume that language performance differences are not the capping factors here.
Complexity vs Performance
In the 2023 evaluation, I used a subjective comparison of different languages. This time, I took a more objective approach by measuring cyclomatic complexity for each implementation. Only the main code files were included in the analysis.

Execution times vs. Cyclomatic Code Complexity (CCN)
The diagram above uses execution time at the 511MB memory configuration, which offers decent performance while still showing distinct differences between languages.
Key observations:
Python and Node.js cluster at the lowest complexity values and show decent execution times. These languages prioritize developer productivity and code simplicity over raw performance.
Go and Rust occupy the middle ground, with moderate complexity and excellent performance. Go’s cyclomatic complexity is notably close to Python and Node.js.
C++ shows the highest complexity but dominates performance, especially at low memory configurations. However, C++’s dependency management and compilation complexity make it impractical for most business use cases.
Java isn’t as disappointing this time, thanks to virtual threads. Still, the performance and complexity combination doesn’t justify its use in this scenario.
Conclusion
Deploying Lambda functions within a VPC and accessing S3 exclusively through VPC endpoints provided greater performance improvements than expected. This eliminated the S3 warm-up effect, providing consistent latency from the first request. S3 Express One Zone, however, showed no measurable advantage over Standard S3 in this workload, suggesting our benchmark doesn’t stress the system enough to reveal its benefits.
Every language now runs successfully at 128MB, with smooth and predictable scaling curves. Java’s virtual threads stand out as the only major language feature change, dramatically improving its concurrency performance. Other gains come from runtime upgrades and more disciplined code optimization.
The AWS SDK bundled with Node.js Lambda runtime provides native async support with no additional dependencies. Python’s boto3, also bundled with the runtime, lacks this capability — requiring third-party libraries like aioboto3. This adds both packaging overhead and performance penalties, as aioboto3 wraps boto3 with thread pools rather than providing true async operations. AWS is developing a new AWS Python SDK to address this limitation.
Final Words
Once again, this has been a fun, laborious, yet educational experiment. I encourage you to read the previous blog series and experiment with the provided code! I already have ideas for the next iteration, so stay tuned for future revisions. Here are a few final notes:
- If you spot a mistake or have ideas for improving the code, please go ahead and let me know by opening an issue on the relevant GitHub repository.
- If you’re curious about how some other programming language would perform in this benchmark, I suggest giving it a try and putting the implementation together. Share your repository with me, and I can include that implementation in a follow-up post with additional languages.
Links to GitHub repositories: