Configure custom rate limiters with the RateLimiter facade, apply them to API routes with the throttle middleware, and handle high-traffic scenarios with Redis-backed limiting.
Laravel’s rate limiting is built on Illuminate\Cache\RateLimiting\Limit and the RateLimiter facade. Internally, a counter is stored in the cache driver (file or Redis by default) and incremented on each matching request. When a request arrives, the throttle middleware executes the closure you defined with RateLimiter::for(). If the limit has been reached, Laravel returns 429 Too Many Requests automatically.
Define your rate limiters in the boot() method of App\Providers\AppServiceProvider.
<?phpnamespace App\Providers;use Illuminate\Cache\RateLimiting\Limit;use Illuminate\Http\Request;use Illuminate\Support\Facades\RateLimiter;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{ public function boot(): void { RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); }); }}
The first argument to RateLimiter::for() is the limiter name — you reference this name in the throttle middleware. The closure must return a Limit instance (or an array of Limit instances).
The throttle middleware automatically adds rate limit headers to every response.
Header
Description
X-RateLimit-Limit
Total requests allowed in the window
X-RateLimit-Remaining
Requests remaining in the current window
Retry-After
Seconds until the next request is allowed (429 responses only)
X-RateLimit-Reset
Unix timestamp when the limit resets
HTTP/1.1 429 Too Many RequestsX-RateLimit-Limit: 60X-RateLimit-Remaining: 0Retry-After: 45X-RateLimit-Reset: 1717000000Content-Type: application/json{ "message": "Too Many Requests."}
Use after() when you only want to count certain responses toward the limit. The callback receives the response and should return true if the response should be counted.
use Symfony\Component\HttpFoundation\Response;RateLimiter::for('resource-lookup', function (Request $request) { return Limit::perMinute(10) ->by($request->user()?->id ?: $request->ip()) ->after(function (Response $response) { return $response->getStatusCode() === 404; });});
This pattern prevents enumeration attacks by limiting consecutive 404 responses without penalising requests that return valid resources.
// Current hit count$hits = RateLimiter::attempts($key);// Seconds until the window resets$seconds = RateLimiter::availableIn($key);// Check whether the limit has been exceeded$tooMany = RateLimiter::tooManyAttempts($key, $maxAttempts = 5);// Manually reset the counter (e.g. after logout)RateLimiter::clear($key);
For Redis-optimised throttling with atomic increment operations, call throttleWithRedis() in bootstrap/app.php. This maps the throttle middleware to ThrottleRequestsWithRedis.
throttleWithRedis() requires Redis to be reachable. If the Redis connection fails, requests may be rejected. Monitor your Redis instance and configure appropriate timeouts.
Redis-backed rate limiting provides:
Horizontal scaling — counters are shared across multiple server instances