DEV Community

Insight 105
Insight 105

Posted on

On Web Framework Performance: A .NET 10 Reality Check

What TechEmpower's Round 23 benchmarks reveal about choosing the right framework for scale.

Quick thought experiment: you're building a microservice that needs to handle 100,000 requests per second with sub-10ms P99 latency. Your options are Express.js on Node.js, or ASP.NET Core Minimal APIs on .NET 10.

If you picked Express purely based on "that's what we know"—well, I've got some news about your infrastructure costs.

The Minimal API Value Proposition

.NET historically suffered from what I'll politely call "ceremony addiction." Building a simple HTTP endpoint required Controllers, Action attributes, dependency injection configuration files, and enough boilerplate to make enterprise Java developers feel right at home.

ASP.NET Core Minimal APIs threw that entire pattern out the window. Here's a complete, production-viable API:

var app = WebApplication.Create();

app.MapGet("/", () => "Hello, World");

app.MapGet("/users/{id}", async (int id, DbContext db) => 
    await db.Users.FindAsync(id) is User user 
        ? Results.Ok(user) 
        : Results.NotFound());

app.Run();
Enter fullscreen mode Exit fullscreen mode

Done. No controllers, no startup configuration sprawl, no architectural astronautics. It reads like Express, except—and here's where it gets interesting—it's meaningfully faster.

The Benchmark Situation

TechEmpower's Round 23 benchmarks (February 2025) show a performance gap that's grown substantially with .NET 9[1]:

Plaintext Test (Synthetic Maximum Throughput):

  • ASP.NET Core (.NET 9): 27,530,836 requests/second
  • Fastify (Node.js): 1,175,038 requests/second
  • Express (Node.js): 279,922 requests/second

That's a 23.4x performance difference in raw throughput. But here's the nuance: this is a synthetic benchmark designed to stress-test frameworks at their theoretical limits.

JSON Serialization (More Realistic):

  • ASP.NET Core: 2,546,481 req/s
  • Fastify: 844,960 req/s
  • Gap: 3.0x — still significant, but the margin narrows with real work.

Single Database Query:

  • ASP.NET Core: 844,156 req/s
  • Fastify: 437,129 req/s
  • Gap: 1.9x — real-world I/O scenarios show smaller but meaningful advantages.

The pattern emerges: .NET's advantage is most dramatic in compute-intensive scenarios. In database-bound applications, the gap narrows—but one .NET server still replaces two Node servers. That operational cost difference compounds, especially when you're paying cloud provider bills quarterly.

TechEmpower Round 23 Benchmark Comparison showing .NET 9 vs Node.js performance across Plaintext, JSON, and Database tests

Now, before the Node.js community arrives with pitchforks: yes, Node is "fast enough" for most applications. Absolutely true. But "fast enough" and "optimal" diverge significantly at scale—and .NET 10 (released November 2025) widens the gap further with 49% faster API response times and 67% faster cold starts[2][3].

Vertical Slicing: The Organizational Benefit Nobody Mentions

Traditional Controller-based APIs encourage this structure:

/Controllers/UserController.cs
/Services/UserService.cs  
/Repositories/UserRepository.cs
Enter fullscreen mode Exit fullscreen mode

Looks organized, right? Until you realize implementing one feature requires editing three files across three directories. When requirements change, you're context-switching between folders like you're playing architectural whack-a-mole.

Minimal APIs naturally encourage organizing by feature:

/Features/
  /Users/
    CreateUser.cs       // Complete feature: endpoint + logic
    GetUser.cs          // Self-contained
    DeleteUser.cs       // Everything in one place
Enter fullscreen mode Exit fullscreen mode

Code that changes together lives together. It's not revolutionary—it's just common sense that wasn't previously convenient.

Type Safety Without the TypeScript Tax

JavaScript developers adopt TypeScript to get compile-time type checking, which means:

  • Configuring tsconfig.json (and debugging it when it inevitably breaks)
  • Installing @types/ packages for every dependency
  • Transpiling before runtime
  • Debugging type errors that only exist at build time

C# has type safety. It's native. Nullable reference types prevent null dereferencing at compile time. Generic constraints ensure type compatibility before your code ever runs. Your IDE knows what methods exist without runtime reflection magic.

This isn't superficial tooling—it's a fundamental difference in how errors are prevented.


What This Article Doesn't Tell You

Here's the thing: this is maybe 10% of the Minimal APIs story. Chapter 10 of "Mastering .NET 10" covers:

  • Complete Minimal API architecture with Vertical Slice pattern implementation
  • Performance optimization techniques (including the dreaded N+1 query problem)
  • Authentication, authorization, and middleware configuration
  • Production deployment strategies for Kubernetes and Azure
  • A full working NanoLink URL shortener with benchmarks

I'm not saying .NET is always the right choice. Different contexts have different constraints. But if you're starting a new microservice and choosing Node.js primarily because "it's what everyone uses"—that's cargo cult engineering, not architecture.

The benchmarks are public. The numbers are reproducible. What you do with that information is your decision.


👉 Next up: Full-stack development with a single language—or why maintaining two ecosystems might be optional →


References

[1] TechEmpower. "Web Framework Benchmarks - Round 23." February 2025. https://www.techempower.com/benchmarks/#section=data-r23

Round 23 benchmarks show .NET 9 performance reaching 27.5M requests/second in plaintext tests, with real-world JSON serialization showing 3.0x advantage over Node.js frameworks.

[2] Microsoft. "Native AOT deployment overview." Official Documentation. https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/

Native AOT compilation in .NET provides 67% faster cold starts, critical for serverless and containerized workloads.

[3] Toub, Stephen. "Performance Improvements in .NET" series. Microsoft DevBlogs. https://devblogs.microsoft.com/dotnet/

Annual deep-dive series documenting .NET runtime optimizations, including JIT improvements, PGO (Profile-Guided Optimization), and zero-allocation patterns.

Top comments (0)