Laravel already has Redis support out of the box, so we can use the Redis::eval() method to run Lua scripts.
1. Store the Lua Script (rate_limit.lua)
Put this in app/Services/Redis/rate_limit.lua:
lua
-- KEYS[1] = user key (e.g., "rate_limit:user123")
-- ARGV[1] = limit (max requests)
-- ARGV[2] = window (seconds)
local current = redis.call("INCR", KEYS[1])
if tonumber(current) == 1 then
redis.call("EXPIRE", KEYS[1], ARGV[2])
end
if tonumber(current) > tonumber(ARGV[1]) then
return 0 -- limit exceeded
else
return 1 -- allowed
end
2. Create a Laravel Service Class
Make app/Services/RateLimiter.php:
php
<?php
namespace App\Services;
use Illuminate\Support\Facades\Redis;
class RateLimiter
{
public static function attempt(string $userId, int $limit, int $window): bool
{
$script = file_get_contents(app_path('Services/Redis/rate_limit.lua'));
$key = "rate_limit:{$userId}";
$result = Redis::eval($script, 1, $key, $limit, $window);
return $result === 1;
}
}
3. Use It in a Controller (e.g., API Throttle)
Example in app/Http/Controllers/ApiController.php:
php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\RateLimiter;
class ApiController extends Controller
{
public function handleRequest(Request $request)
{
$userId = $request->user()->id ?? $request->ip();
// Allow max 5 requests per 60 seconds
if (!RateLimiter::attempt($userId, 5, 60)) {
return response()->json(['error' => 'Too Many Requests'], 429);
}
return response()->json(['message' => 'Request successful']);
}
}
Test It:
- Make 5 requests within 60s → allowed
- On the 6th request → returns
429 Too Many Requests
Why This is Powerful
- Uses Redis Lua for atomic, fast rate limiting.
- Works across multiple app servers (not just one PHP instance).
- Easy to tweak per-user, per-IP, or per-API-key.
You can also extend this so different API endpoints can have different rate limits (e.g., /login stricter, /profile looser). See Laravel: rate limiter for different API endpoints

