Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nimanikoo/Dotnet-RateLimiter/llms.txt

Use this file to discover all available pages before exploring further.

Dotnet-RateLimiter is a production-ready, distributed rate limiting infrastructure for .NET 10 APIs. It combines the speed of Redis with the atomicity of Lua scripting to solve the most critical challenge of throttling in multi-instance environments: race conditions and consistency. Whether you’re running a single-node service or a horizontally scaled microservices fleet, Dotnet-RateLimiter ensures every request is counted exactly once — no duplicates, no missed increments, no overruns.

The Distributed Challenge

Standard in-memory rate limiters work well on a single server, but they fundamentally break down the moment you scale out. Consider two API instances running simultaneously: each maintains its own isolated counter. When two requests arrive at the exact same millisecond on different nodes, both servers independently read a counter of 9 (against a limit of 10) and both allow the request — resulting in 11 total requests against a supposed cap of 10.
This is the split-brain problem inherent to all in-memory limiters in distributed systems. The counters are local, but your users are global.
In a microservices architecture, the consequences are real: downstream databases get overwhelmed, third-party API quotas are blown, and SLA guarantees are broken — all because the throttle that was supposed to protect them was enforcing limits only per-instance, not cluster-wide.

The Redis + Lua Solution

Dotnet-RateLimiter moves the “Source of Truth” out of application memory and into Redis, a single shared store accessible by every API instance. Crucially, the counter logic — increment, check, expire — is not handled by the application at all. It is shipped as a Lua script that executes entirely inside Redis itself. Redis guarantees that any Lua script runs as a single atomic operation. No other Redis command can interleave with the script’s execution. This means the classic read-modify-write race condition is completely eliminated:
local current = redis.call('INCR', @key)
if tonumber(current) == 1 then
    redis.call('EXPIRE', @key, @window)
end
if tonumber(current) > tonumber(@maxRequests) then
    return 0
else
    return 1
end
The script increments the counter, sets a TTL on the first request (starting the window), and returns 0 or 1 in a single indivisible operation. No two requests can ever read the same counter state — consistency is 100% guaranteed across every node in the cluster.
Because all logic runs inside Redis, the RedisRateLimiter service in the application is thin: it prepares the Lua script with LuaScript.Prepare(), calls ScriptEvaluateAsync(), and interprets the integer result. There is no application-side locking, no distributed mutex, and no external coordination needed.

Supported Rate Limiting Strategies

Dotnet-RateLimiter ships with five strategies. The distributed Redis limiter is the flagship, but the in-process ASP.NET Core strategies are fully configured and ready to use for scenarios where cluster-wide coordination is not required.

1. Distributed Fixed Window (Redis + Lua)

The primary strategy. Enforces a cluster-wide request limit over a fixed time window using atomic Lua script execution inside Redis. Applied via the [RedisRateLimit] attribute on any controller action. All counter state lives in Redis with automatic TTL expiry.

2. Standard Fixed Window

An in-process ASP.NET Core fixed window limiter registered as "FixedWindowPolicy". Configured with a 5-second window, a permit limit of 5, and a queue limit of 10 using OldestFirst processing order. Applied via [EnableRateLimiting("FixedWindowPolicy")].

3. Sliding Window

An in-process sliding window limiter registered as "SlidingWindowPolicy". Uses a 10-second window divided into 4 segments to smooth out traffic spikes and prevent the burst edge cases that fixed windows can allow at window boundaries. Permit limit of 5, queue limit of 10.

4. Token Bucket

An in-process token bucket limiter registered as "BucketPolicy". Allows controlled burstiness: starts with 5 tokens, replenishes 3 tokens every 5 seconds with AutoReplenishment enabled. Queue limit of 2. Ideal for workloads where short bursts should be permitted within a longer-term average rate.

5. Concurrency Limiter

An in-process concurrency limiter registered as "ConcurrencyPolicy". Limits the number of simultaneous in-flight requests rather than the rate over time — a permit limit of 7 concurrent requests with a queue limit of 3. Protects downstream resources such as databases and external APIs from saturation during traffic spikes.
All four in-process strategies return HTTP 429 Too Many Requests when their limits are exceeded, consistent with the Redis strategy’s response code.

Identity-Aware Rate Limiting

The Redis strategy is not a blunt per-endpoint hammer — it scopes limits intelligently per client identity. The RedisRateLimitingMiddleware resolves client identity before building the Redis key used to track request counts:
  • Authenticated Users: The middleware checks context.User.Identity?.IsAuthenticated. If true, it resolves the client identifier from ClaimTypes.NameIdentifier, falling back to User.Identity.Name, and then to "authenticated_unknown". The userType is set to "user".
  • Anonymous Guests: If the request is unauthenticated, the client’s remote IP address from context.Connection.RemoteIpAddress is used as the identifier. The userType is set to "guest".
  • Granular Scoping per Path: The final Redis key is composed as rate_limit:{userType}:{identityKey}:{request.Path}. This means limits are scoped per user (or IP) and per API path — a user exhausting the limit on one endpoint does not affect their quota on any other endpoint.
This design ensures fair usage across your entire API surface: heavy consumers of one endpoint cannot starve other endpoints or other users.

Observability Stack

Dotnet-RateLimiter includes a full monitoring stack out of the box, requiring no additional configuration to run locally:
  • Health Dashboard at /health-ui: Real-time Redis connectivity status, latency, system liveness checks, and a circuit-breaker fail-fast mechanism for infrastructure dependencies. Evaluated every 5 seconds.
  • RedisInsight UI at port 8001: A visual interface to inspect rate-limit keys, watch counters increment and decrement in real time, and observe TTL expiry managed by the Lua engine.
  • Swagger UI: Auto-generated OpenAPI documentation for all endpoints, available in the Development environment.

Next Steps

Quickstart

Add distributed rate limiting to your ASP.NET Core 10 project in under five minutes.

Strategies

Explore all five rate limiting strategies and when to use each one.

Deployment

Run the full API, Redis, and RedisInsight stack with a single Docker Compose command.

API Reference

Browse the full attribute, service, and middleware API surface.

Build docs developers (and LLMs) love