Minimal APIs have become a popular choice for building lightweight HTTP services in ASP.NET Core. By reducing boilerplate code and simplifying endpoint definitions, they enable developers to create fast, maintainable APIs with minimal configuration.
However, simply using Minimal APIs doesn't automatically guarantee high performance. Efficient routing, optimized JSON serialization, proper dependency injection, caching, and asynchronous programming all play an important role in building scalable production applications.
In this article, you'll learn practical techniques for optimizing Minimal APIs in ASP.NET Core 11, explore common performance pitfalls, and understand how to evaluate improvements using a structured benchmarking methodology.
Note: This article focuses on optimization techniques and benchmark methodology. It intentionally avoids presenting fabricated benchmark results.
Why Performance Optimization Matters
Every HTTP request consumes CPU, memory, network bandwidth, and database resources.
Poorly optimized APIs can lead to:
Small optimizations become increasingly valuable as request volume grows.
What Are Minimal APIs?
Minimal APIs allow endpoints to be defined without controllers.
Traditional controller:
[ApiController]
[Route("api/products")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return Ok();
}
}
Minimal API equivalent:
var app = builder.Build();
app.MapGet("/products", () =>
{
return Results.Ok();
});
app.Run();
The reduced abstraction makes applications easier to understand while lowering framework overhead.
Return Typed Results
Instead of returning anonymous objects directly, use typed results.
app.MapGet("/products/{id}", (int id) =>
{
return Results.Ok(new
{
Id = id
});
});
Benefits include:
Better OpenAPI metadata
Stronger typing
Improved readability
Use Asynchronous Endpoints
Avoid synchronous database operations.
app.MapGet("/products", async (
AppDbContext db) =>
{
return await db.Products
.AsNoTracking()
.ToListAsync();
});
Asynchronous I/O improves scalability by preventing request threads from blocking while waiting for database or network operations.
Disable Tracking for Read Operations
Read-only endpoints should avoid change tracking.
var products = await db.Products
.AsNoTracking()
.ToListAsync();
This reduces memory usage and CPU overhead.
Return Only Required Data
Avoid returning entire entities.
Instead of:
return await db.Products.ToListAsync();
Project only the required fields.
return await db.Products
.Select(p => new
{
p.Id,
p.Name,
p.Price
})
.ToListAsync();
Smaller payloads reduce serialization time and network traffic.
Use Route Groups
Route groups simplify endpoint organization.
var products = app.MapGroup("/products");
products.MapGet("/", GetProducts);
products.MapPost("/", CreateProduct);
Grouping endpoints improves maintainability without affecting request routing performance.
Inject Dependencies Efficiently
Inject only the services required by an endpoint.
app.MapGet("/products",
async (
AppDbContext db,
ILogger<Program> logger) =>
{
logger.LogInformation("Fetching products");
return await db.Products.ToListAsync();
});
Avoid resolving unnecessary services on every request.
Add Response Compression
Enable response compression for large payloads.
builder.Services.AddResponseCompression();
var app = builder.Build();
app.UseResponseCompression();
Compression reduces bandwidth usage, particularly for JSON responses.
Cache Frequently Requested Data
Use distributed or in-memory caching for data that changes infrequently.
app.MapGet("/categories",
async (
IDistributedCache cache) =>
{
var json =
await cache.GetStringAsync("categories");
return Results.Ok(json);
});
Caching reduces database load and improves response times.
Apply Rate Limiting
Protect endpoints from excessive traffic.
app.MapGet("/products", GetProducts)
.RequireRateLimiting("api");
Rate limiting improves application stability during traffic spikes.
Configure JSON Serialization
ASP.NET Core uses System.Text.Json by default.
Customize serialization options when appropriate.
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.WriteIndented = false;
});
Avoid unnecessary formatting in production responses to reduce payload size.
End-to-End Request Flow
An optimized request typically follows these steps:
Client sends a request.
Routing selects the endpoint.
Rate limiting validates the request.
Cache is checked.
Database is queried if necessary.
Data is projected into lightweight objects.
JSON is serialized.
Response compression is applied.
Response is returned.
Each optimization contributes to overall application performance.
Optimization Techniques Comparison
| Technique | Primary Benefit | Best For |
|---|
| Async endpoints | Higher scalability | Database and HTTP calls |
| AsNoTracking() | Lower memory usage | Read-only queries |
| Projection | Smaller payloads | APIs |
| Response compression | Reduced bandwidth | Large JSON responses |
| Caching | Faster responses | Frequently requested data |
| Route groups | Better organization | Large APIs |
| Rate limiting | Resource protection | Public APIs |
| Typed results | Better API metadata | Production APIs |
Performance Evaluation Methodology
The research brief focuses on optimization but does not provide benchmark data. Evaluate changes using the following methodology.
Test Environment
Maintain consistency for:
.NET SDK version
ASP.NET Core version
Database
Hardware
Operating system
Build configuration
Test Scenarios
Compare:
Controller-based APIs
Minimal APIs
Cached vs uncached responses
Tracking vs no-tracking queries
Small and large payloads
Compressed vs uncompressed responses
Metrics to Measure
Collect:
Requests per second
Average response time
P95 and P99 latency
Memory allocations
CPU utilization
Database query count
Response size
Useful Tools
Useful tools include:
BenchmarkDotNet
k6
Bombardier
dotnet-counters
dotnet-trace
Application Insights
MiniProfiler
Benchmark using production-like request patterns rather than isolated requests.
Best Practices
Use asynchronous endpoints for I/O-bound operations.
Apply AsNoTracking() to read-only queries.
Return only required fields.
Cache frequently requested data.
Keep endpoint handlers focused.
Enable response compression where appropriate.
Monitor request latency and error rates.
Test performance with representative workloads.
Common Mistakes
| Mistake | Impact |
|---|
| Returning entire entities | Larger payloads |
| Blocking asynchronous operations | Reduced scalability |
| Ignoring caching opportunities | Increased database load |
| Excessive dependency injection | Unnecessary overhead |
| Returning formatted JSON in production | Larger responses |
| Skipping load testing | Undetected bottlenecks |
Troubleshooting
High Response Times
Review:
High Memory Usage
Check:
Entity tracking
Large response objects
Excessive allocations
Cache configuration
Low Throughput
Investigate:
Blocking operations
Database contention
Thread pool utilization
Request queue length
Use runtime diagnostics to identify bottlenecks before optimizing application code.
FAQs
Are Minimal APIs faster than controllers?
Minimal APIs generally reduce framework overhead, but the overall performance of an application is usually determined by database access, serialization, networking, and business logic rather than routing alone.
Should I use Minimal APIs for every project?
Not necessarily. Minimal APIs are well suited for lightweight services, microservices, and small to medium APIs. Larger applications may still benefit from controllers when advanced features or conventions are needed.
Does AsNoTracking() improve performance?
Yes. For read-only queries, it reduces change-tracking overhead, lowering memory usage and CPU consumption.
Should every endpoint use caching?
No. Cache data that is expensive to compute or retrieve and changes infrequently. Frequently changing data may not benefit from caching.
How should I measure API performance?
Use tools such as BenchmarkDotNet for component benchmarks and load-testing tools like k6 or Bombardier to evaluate end-to-end API performance under realistic workloads.
Conclusion
Minimal APIs provide a streamlined approach to building modern ASP.NET Core services, but achieving high performance requires more than reducing boilerplate code. Efficient data access, asynchronous programming, response compression, caching, and careful dependency management all contribute to scalable applications.
By applying these optimization techniques and validating them with structured performance testing, you can build Minimal API applications that remain responsive, efficient, and production-ready as traffic and complexity increase.