Skip to main content

How Laravel rate limiting works

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.

Defining rate limiters in AppServiceProvider

Define your rate limiters in the boot() method of App\Providers\AppServiceProvider.
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).

Defining limits per user, plan, or IP

Authenticated users vs guests

Per-plan limits

Global IP-based limit

Throttle all requests from a single IP address regardless of the route.

Combining multiple limits

Return an array of Limit instances to enforce all limits simultaneously. Laravel returns 429 as soon as any one of them is exceeded.
When multiple limits share the same by key, they will overwrite each other in the cache. Add a prefix to keep them separate.

Attaching limiters to routes with the throttle middleware

Pass the limiter name to the throttle middleware.

Registering in bootstrap/app.php

In Laravel 11+, middleware is managed in bootstrap/app.php.

Full API example

1

Define the limiters

Add multiple limiters to AppServiceProvider.
2

Apply middleware to routes

Response headers

The throttle middleware automatically adds rate limit headers to every response.

Returning a custom response

Response-based rate limiting

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.
This pattern prevents enumeration attacks by limiting consecutive 404 responses without penalising requests that return valid resources.

Manual rate limiting with RateLimiter::attempt()

When you need to apply rate limiting outside of the throttle middleware — for example, inside a controller action — use RateLimiter::attempt().

Inspecting and resetting counters

Login throttling example

Redis-backed rate limiting

Switching the cache driver to Redis automatically makes the throttle middleware use Redis as its backing store.

Configuring Redis as the cache driver

Using throttleWithRedis

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
  • Precision — atomic operations prevent race conditions
  • Automatic cleanup — Redis TTLs expire counters without additional maintenance

Caching

Configure Redis and other cache drivers used by the rate limiter.
Last modified on March 29, 2026