Rate limiting routes — throttle middleware, RateLimiter facade
Concept
Rate limiting routes controls how many requests a client can make to specific routes within a time window. Laravel provides the throttle middleware and the RateLimiter facade for flexible, named rate limiters.
throttle:N,M middleware: throttle:60,1 — 60 requests per 1 minute per IP. The simplest form. Can be applied to individual routes or groups.
Named rate limiters: Define complex rate limiting logic in AppServiceProvider::boot() (or RouteServiceProvider::boot()) using RateLimiter::for('name', callback). Apply with throttle:name.
RateLimiter::for callback: Receives a Request and returns a Limit or array of Limits. Limit::perMinute(N) — N requests per minute. Limit::perHour(N) — N requests per hour. Limit::perDay(N) — N requests per day. .by($key) — differentiate rate limits by user ID, IP, or any string.
Multiple limits: Return an array of Limit objects — all limits must be satisfied. [Limit::perMinute(10)->by($request->ip()), Limit::perMinute(20)->by($request->user()?->id ?? $request->ip())] — IP-based AND user-based limits simultaneously.
Custom response: ->response(fn() => response('Too many requests', 429)).
Headers: When throttle middleware is applied, responses include X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After headers — standard rate limit signaling for API clients.
Code Example
<?php
// In AppServiceProvider::boot() or RouteServiceProvider::boot()
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
RateLimiter::for('api', function(\Illuminate\Http\Request $request) {
return Limit::perMinute(60)
->by($request->user()?->id ?: $request->ip());
});
RateLimiter::for('uploads', function(\Illuminate\Http\Request $request) {
return [
Limit::perMinute(5)->by($request->user()?->id ?: $request->ip()),
Limit::perDay(50)->by($request->user()?->id ?: $request->ip()),
];
});
RateLimiter::for('login', function(\Illuminate\Http\Request $request) {
return Limit::perMinute(5)
->by($request->input('email') . '|' . $request->ip())
->response(fn() => response()->json([
'message' => 'Too many login attempts. Please try again in 60 seconds.',
], 429));
});
// Apply rate limiters in routes
Route::middleware('throttle:api')->group(function() {
Route::apiResource('products', ProductController::class);
Route::apiResource('orders', OrderController::class);
});
Route::post('/login', LoginController::class)->middleware('throttle:login');
Route::post('/upload', UploadController::class)->middleware('throttle:uploads');
// Simple inline rate limit (60 requests per minute per IP)
Route::get('/search', SearchController::class)->middleware('throttle:60,1');
// Route group with rate limiting
Route::prefix('api/v1')
->middleware(['auth:sanctum', 'throttle:api'])
->group(function() {
Route::get('/user', fn() => auth()->user());
Route::post('/orders', [OrderController::class, 'store']);
});