Public APIs are constantly exposed to unpredictable traffic. Whether it's accidental overuse, poorly designed client applications, or malicious attacks, excessive requests can degrade performance, increase infrastructure costs, and even make an application unavailable.

Rate limiting helps protect APIs by controlling how many requests a client can make within a specified period. Starting with .NET 7, ASP.NET Core includes built-in rate limiting middleware, making it easier to implement robust traffic control without relying on third-party libraries.

In this article, you'll learn how rate limiting works, explore the available algorithms, and discover best practices for building secure and scalable ASP.NET Core APIs.

Why Rate Limiting Matters

Consider a public product API that receives thousands of requests from different clients.

Without rate limiting:

Clients
   │
ASP.NET Core API
   │
Database

A single client could send excessive requests, consuming server resources and affecting other users.

With rate limiting:

Clients
   │
Rate Limiter
   │
ASP.NET Core API
   │
Database

The application accepts requests within defined limits while rejecting excessive traffic with an HTTP 429 Too Many Requests response.

Rate limiting helps:

Built-In Rate Limiting Middleware

ASP.NET Core includes rate limiting middleware in the Microsoft.AspNetCore.RateLimiting package.

Register rate limiting during application startup:

using System.Threading.RateLimiting;

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("fixed", limiter =>
    {
        limiter.PermitLimit = 100;
        limiter.Window = TimeSpan.FromMinutes(1);
    });
});

Enable the middleware:

app.UseRateLimiter();

Apply the policy to an endpoint:

app.MapGet("/products", () => Results.Ok())
   .RequireRateLimiting("fixed");

This configuration limits clients to 100 requests per minute for the protected endpoint.

Fixed Window Rate Limiting

The fixed window algorithm divides time into fixed intervals.

Example:

A client can make up to 100 requests during the current minute. Once the limit is reached, additional requests are rejected until the next window begins.

Best Use Cases

Its simplicity makes it easy to configure, although it can allow request bursts at window boundaries.

Sliding Window Rate Limiting

Sliding window limiting distributes requests more evenly over time.

Instead of resetting all counters simultaneously, it continuously evaluates activity over the most recent time period.

Benefits include:

This approach is often preferable for APIs with fluctuating traffic.

Token Bucket Algorithm

The token bucket algorithm provides greater flexibility.

Tokens are added to a bucket at a fixed rate.

Each incoming request consumes one token.

If tokens remain:

If no tokens remain:

This algorithm allows short traffic bursts while maintaining an average request rate.

It's commonly used for public APIs that experience occasional spikes in demand.

Concurrency Limiting

Some operations are expensive regardless of request frequency.

Concurrency limiting controls how many requests execute simultaneously.

Example configuration:

builder.Services.AddRateLimiter(options =>
{
    options.AddConcurrencyLimiter("concurrent", limiter =>
    {
        limiter.PermitLimit = 20;
    });
});

Only 20 requests are processed concurrently, while additional requests wait or are rejected depending on the configuration.

This strategy works well for resource-intensive endpoints.

Choosing a Partition Key

Rate limiting policies are typically applied per client rather than globally.

Common partition keys include:

Selecting the appropriate partition ensures one client cannot exhaust resources allocated to others.

For multi-tenant applications, API keys or tenant identifiers usually provide better isolation than IP addresses.

Handling Rejected Requests

When a request exceeds the configured limit, the API should return a clear response.

Typical response:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

Including the Retry-After header helps clients determine when they can safely retry.

Well-designed APIs document their rate limits and expected behavior so client applications can respond appropriately.

Rate Limiting Strategies Compared

StrategyBest ForAdvantagesLimitations
Fixed WindowSimple APIsEasy to configureAllows burst traffic at window boundaries
Sliding WindowPublic APIsSmoother request distributionSlightly more complex
Token BucketVariable workloadsSupports controlled burstsRequires token management
Concurrency LimiterResource-intensive endpointsProtects expensive operationsDoesn't directly limit request frequency

Best Practices

Common Mistakes

Applying the Same Limit Everywhere

Not every endpoint has the same cost. A lightweight health check and a report generation endpoint shouldn't share identical limits. Tailor policies to the workload.

Using Only IP-Based Limits

Many users may share the same public IP address, especially in corporate environments or behind proxies. Authenticated user IDs or API keys often provide fairer rate limiting.

Ignoring Monitoring

Without monitoring, it's difficult to determine whether clients are hitting limits because of abuse or legitimate usage. Track rejected requests and adjust policies based on actual traffic patterns.

Treating Rate Limiting as a Security Solution

Rate limiting helps reduce abuse but doesn't replace authentication, authorization, input validation, or web application firewalls. It should be part of a broader API security strategy.

Conclusion

Rate limiting is an essential component of modern API design. By controlling request volume, it protects applications from abuse, improves resource utilization, and ensures fair access for all clients.

ASP.NET Core's built-in rate limiting middleware makes it straightforward to implement policies such as fixed window, sliding window, token bucket, and concurrency limiting without relying on external libraries. Choosing the right strategy depends on your application's traffic patterns, endpoint characteristics, and scalability requirements.

When combined with authentication, monitoring, and well-designed API policies, rate limiting helps build secure, reliable, and scalable ASP.NET Core applications that continue to perform well under both expected and unexpected traffic loads.