symfony/rate-limiter
Symfony Rate Limiter component implementing token bucket rate limiting. Configure limiters via a factory and use reserve() to wait for tokens or consume() to attempt immediately. Supports pluggable storage like in-memory for controlling request/input/output rates.
throttle middleware (Symfony’s RateLimiter is its upstream dependency), ensuring consistency in behavior and debugging.InMemoryStorage (for single-instance Laravel apps), RedisStorage, or custom backends, fitting Laravel’s caching layer (Redis, database, file).consume() (non-blocking) integrates with Laravel’s middleware pipeline, while reserve()->wait() can be used in CLI/queue workers (e.g., Laravel Horizon).CompoundRateLimiterFactory enables complex rules (e.g., "limit to 100 requests/hour and 10 requests/minute"), useful for multi-tenant SaaS.Retry-After headers (RFC 6585), reducing client-side retry logic in APIs.Key Misalignment:
throttle middleware already uses Symfony’s RateLimiter under the hood. This package is redundant for basic API rate limiting unless you need:
Cache facade (Redis, database, file) via CacheStorage.throttle middleware out of the box (no rewrite needed).options-resolver and contracts (already bundled with Laravel).spatie/laravel-rate-limiting is a wrapper for this).config/rate_limits.php or environment variables (e.g., .env).'rate_limits' => [
'login' => [
'policy' => 'token_bucket',
'limit' => 5,
'interval' => '5 minutes',
],
],
throttle middleware:
use Symfony\Component\RateLimiter\RateLimiterFactory;
use Symfony\Component\RateLimiter\Storage\CacheStorage;
$factory = new RateLimiterFactory([
'id' => 'api',
'policy' => 'token_bucket',
'limit' => 100,
'interval' => '1 hour',
], new CacheStorage(app('cache')));
$limiter = $factory->create();
if (!$limiter->consume(1)->isAccepted()) {
abort(429, 'Too many requests');
}
| Risk | Mitigation | Severity |
|---|---|---|
| Distributed Storage | Redis/Memcached required for multi-instance Laravel (e.g., Kubernetes). | High |
| PHP 8.1+ Requirement | Laravel 10+ enforces PHP 8.1+, so no risk for modern stacks. | Low |
| Token Bucket Complexity | Debugging retryAfter or reserve() logic may require Symfony docs. |
Medium |
| Storage Backend Limits | InMemoryStorage is single-instance only; Redis required for scaling. |
High |
| Middleware Overhead | Non-blocking consume() adds minimal latency (~1ms for Redis). |
Low |
| Compound Limits | CompoundRateLimiterFactory adds complexity; test thoroughly in staging. |
Medium |
Critical Questions for TPM:
InMemoryStorage or database-backed CacheStorage suffices.CompoundRateLimiterFactory and careful testing.reserve()->wait() is ideal for blocking operations (e.g., Laravel Horizon jobs).CacheStorage with a fallback to InMemoryStorage.throttle middleware (Symfony’s RateLimiter is already used internally).Cache facade for storage (Redis, database, file).reserve()->wait() in Laravel Horizon jobs to prevent overloading external APIs.config() or environment variables (e.g., APP_RATE_LIMIT_PRO=10000).Stack Misalignment:
sleep() delays).throttle middleware for a single endpoint (e.g., /login).InMemoryStorage (single-instance) or CacheStorage (Redis).throttle middleware to RateLimiter.Retry-After headers to API responses.retryAfter values and adjust token bucket policies.Example Migration:
// Before (Laravel's throttle middleware)
Route::middleware(['throttle:5,1'])->group(function () {
Route::post('/login', [LoginController::class, 'store']);
});
// After (Symfony RateLimiter)
Route::group(['middleware' => function ($request, $next) {
$limiter = app(RateLimiterFactory::class)->create('login');
if (!$limiter->consume(1)->isAccepted()) {
return response()->json(['error' => 'Too many attempts'], 429)
->header('Retry-After', $limiter->getRetryAfter()->format('U'));
}
return $next($request);
}], function () {
Route::post('/login', [LoginController::class, 'store']);
});
| Component | Compatibility | Notes |
|---|---|---|
| Laravel 10+ | ✅ Full support | Uses Symfony 6.4+ |
| Laravel 11+ | ✅ Full support | Uses Symfony 7.0+ |
| Redis/Memcached | ✅ Required for distributed storage | CacheStorage wrapper |
| Database (Cache) | ✅ Supported via Laravel’s Cache facade |
Slower than Redis |
| File Storage | ✅ Supported (single-instance only) | Not recommended for production |
| PHP 8.1+ | ✅ Required | Laravel 10+ enforces this |
| Symfony 6.4+/7.0+ | ✅ Direct dependency | No conflicts with Laravel |
| Laravel Queues | ✅ reserve()->wait() works in Horizon jobs |
Prevents queue overload |
| API Clients | ✅ Retry-After header compliance (RFC 6585) |
Reduces client-side retries |
throttle middleware for auth/payment endpoints.CacheStorage with Redis for distributed Laravel.reserve()->wait() to Horizon jobs calling external APIs.CompoundRateLimiterFactory for per-user + per-IP limits.How can I help you explore Laravel packages today?