Public APIs are constantly exposed to automated bots, accidental traffic spikes, and abusive clients. Without proper safeguards, a single client can overwhelm your application, consume server resources, and degrade performance for every other user.
ASP.NET Core includes built-in rate limiting middleware that makes it easy to control how many requests a client can send within a given time period. By applying appropriate rate limiting policies, you can improve application stability, prevent denial-of-service scenarios, and ensure fair resource usage.
Rather than implementing custom throttling logic, this article explains how to use the built-in ASP.NET Core rate limiting middleware, choose the right algorithm, and configure production-ready policies.
Note: Rate limiting is not a replacement for authentication, authorization, or a Web Application Firewall (WAF). It complements these security measures by controlling request frequency.
Why API Rate Limiting Matters
Without rate limiting, APIs are vulnerable to:
Accidental traffic spikes
Brute-force login attempts
API abuse
Credential stuffing attacks
Excessive resource consumption
Increased infrastructure costs
Reduced application availability
Limiting request rates helps maintain consistent performance even during periods of unusually high traffic.
Common Rate Limiting Scenarios
Rate limiting can be applied to:
Login endpoints
Public APIs
File upload endpoints
Search APIs
Payment APIs
Password reset endpoints
Third-party integrations
AI-powered endpoints
Different endpoints often require different request limits depending on their workload and business requirements.
Rate Limiting Algorithms
ASP.NET Core supports multiple rate limiting strategies.
| Algorithm | Best For |
|---|
| Fixed Window | Simple APIs with predictable traffic |
| Sliding Window | Smoother request distribution |
| Token Bucket | APIs with occasional traffic bursts |
| Concurrency Limiter | Limiting simultaneous requests |
Each algorithm provides different trade-offs between fairness, burst handling, and implementation complexity.
Installing the Rate Limiting Middleware
The rate limiting middleware is included with modern versions of ASP.NET Core.
Register the middleware during application startup.
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter(
"default",
policy =>
{
policy.PermitLimit = 100;
policy.Window = TimeSpan.FromMinutes(1);
policy.QueueLimit = 0;
});
});
This configuration allows up to 100 requests per minute before additional requests are rejected.
Enabling Rate Limiting
Enable the middleware within the request pipeline.
var app = builder.Build();
app.UseRateLimiter();
app.MapControllers();
app.Run();
Without calling UseRateLimiter(), configured policies won't be enforced.
Applying Rate Limiting to Endpoints
Policies can be applied to individual endpoints.
app.MapGet("/weather", () =>
{
return Results.Ok();
})
.RequireRateLimiting("default");
This approach allows different APIs to use different request limits.
Using a Sliding Window Policy
Sliding window limiting distributes requests more evenly.
builder.Services.AddRateLimiter(options =>
{
options.AddSlidingWindowLimiter(
"sliding",
policy =>
{
policy.PermitLimit = 60;
policy.Window = TimeSpan.FromMinutes(1);
policy.SegmentsPerWindow = 6;
});
});
Unlike a fixed window, the sliding window gradually expires requests instead of resetting all limits simultaneously.
Limiting Concurrent Requests
Some operations are expensive rather than frequent.
Use a concurrency limiter for these scenarios.
builder.Services.AddRateLimiter(options =>
{
options.AddConcurrencyLimiter(
"uploads",
policy =>
{
policy.PermitLimit = 5;
policy.QueueLimit = 10;
});
});
This configuration ensures that only five upload requests execute simultaneously.
Rate Limiting Request Flow
flowchart LR
A[Client Request]
B[Rate Limiter]
C{Limit Exceeded?}
D[Process Request]
E[Return HTTP 429]
A --> B
B --> C
C -->|No| D
C -->|Yes| E
When a client exceeds the configured policy, the middleware immediately returns an HTTP 429 (Too Many Requests) response.
Choosing Appropriate Limits
The ideal request limit depends on the endpoint.
| Endpoint | Example Limit |
|---|
| Login API | 5 requests/minute |
| Search API | 30 requests/minute |
| Public API | 100 requests/minute |
| File Upload | 10 requests/minute |
| Payment API | 20 requests/minute |
These values are examples. Monitor production traffic before finalizing rate limits.
Handling Rejected Requests
Customize responses for rejected requests.
builder.Services.AddRateLimiter(options =>
{
options.OnRejected = async (context, _) =>
{
context.HttpContext.Response.StatusCode = 429;
await context.HttpContext.Response.WriteAsync(
"Rate limit exceeded.");
};
});
Providing a clear error response helps clients understand why their requests were rejected.
Common Production Mistakes
| Problem | Root Cause |
|---|
| Legitimate users blocked | Limits configured too aggressively |
| No protection against abuse | Rate limiting disabled |
| High server load | Limits set too high |
| Shared users affected | Using IP-only identification behind proxies |
| Unexpected request failures | Policies applied to incorrect endpoints |
| Poor client experience | Missing Retry-After information |
Most rate limiting issues result from poorly chosen thresholds rather than the middleware itself.
Best Practices
Apply different limits to different endpoints.
Use stricter limits for authentication APIs.
Monitor HTTP 429 responses.
Test policies using realistic production traffic.
Combine rate limiting with authentication and authorization.
Return meaningful error responses for rejected requests.
Review limits regularly as traffic patterns evolve.
Common Anti-Patterns
Avoid these common mistakes:
Applying identical limits to every endpoint.
Disabling rate limiting in production.
Using extremely restrictive limits without testing.
Ignoring reverse proxy configuration.
Assuming rate limiting prevents every denial-of-service attack.
Treating rate limiting as a replacement for security controls.
FAQ
Which rate limiting algorithm should I choose?
Fixed Window is suitable for many APIs. Sliding Window provides smoother traffic control, Token Bucket handles bursts effectively, and Concurrency Limiter is ideal for resource-intensive operations.
What HTTP status code is returned when the limit is exceeded?
The middleware returns HTTP 429 (Too Many Requests), indicating that the client has exceeded the configured request limit.
Can different endpoints use different limits?
Yes. ASP.NET Core supports multiple named policies, allowing each endpoint or route group to enforce its own request limits.
Does rate limiting work with reverse proxies?
Yes, but ensure client IP addresses are forwarded correctly using forwarded headers. Otherwise, multiple users may appear to originate from the same IP address.
Conclusion
Rate limiting is a fundamental part of building secure and reliable APIs. By controlling request frequency, you can protect your ASP.NET Core applications from abuse, reduce unnecessary resource consumption, and maintain a consistent experience for legitimate users.
The built-in ASP.NET Core rate limiting middleware provides flexible algorithms, endpoint-specific policies, and straightforward configuration without requiring third-party libraries. When combined with authentication, monitoring, and proper infrastructure design, it helps create resilient APIs that remain responsive even under heavy traffic.