Laravel Rate Limiting & Throttling by Deepak Dubey


Laravel Rate Limiting & Throttling Explained: Token Bucket, Sliding Window & Real-World Use Cases

Most developers treat rate limiting like a checkbox. That’s lazy thinking. If you're building serious products — especially APIs, SaaS, or fintech — rate limiting is not optional. It’s infrastructure protection. Let’s go deep.

Laravel Rate Limiting & Throttling


  • Laravel
  • Rate Limiting
  • API Security
  • Throttling

What Is Rate Limiting (And Why It Actually Matters)

Rate limiting controls how many requests a client can make in a given time window. Without it:

  • Bots will hammer your API
  • Attackers will brute force login
  • Scrapers will steal your data
  • One bad client can overload your entire server

Laravel provides built-in throttling via middleware and a flexible RateLimiter class. But understanding the algorithms behind it makes you better than 90% of developers.

How Laravel Implements Rate Limiting

Laravel uses:

Illuminate\Support\Facades\RateLimiter
    

Under the hood, it relies on:

  • Cache (Redis recommended in production)
  • Atomic operations
  • Time-based decay

The default algorithm behaves like a fixed window counter, but you can implement:

  • Token Bucket
  • Sliding Window
  • Dynamic per-user limits
  • Role-based limits
  • IP-based or API-key-based limits

Fixed Window (Default Laravel Behavior)

How It Works

Example: 60 requests per minute.

  • Window starts at 10:00:00
  • User makes 60 requests → allowed
  • At 10:00:59 → blocked
  • At 10:01:00 → counter resets

Problem: It allows bursts at boundary edges. Example: 60 requests at 10:00:59 and 60 more at 10:01:01 → 120 requests in 2 seconds.

Token Bucket Algorithm

Concept

Think of it like a bucket holding tokens.

  • Bucket capacity = max requests
  • Tokens refill gradually
  • Each request consumes 1 token
  • If no tokens → request denied

Why It's Better:

  • Allows small bursts
  • Smooth traffic control
  • More realistic control mechanism

Implementing Token Bucket in Laravel

Laravel doesn’t natively provide full token bucket logic — so we simulate it using Redis + RateLimiter.

Step 1: Create Custom Middleware

php artisan make:middleware TokenBucketLimiter
      

Step 2: Middleware Code

ip();
        $currentTime = time();

        $bucket = Cache::get($key, [
            'tokens' => $this->capacity,
            'last_refill' => $currentTime
        ]);

        // Calculate tokens to refill
        $elapsed = $currentTime - $bucket['last_refill'];
        $refill = $elapsed * $this->refillRate;

        $bucket['tokens'] = min(
            $this->capacity,
            $bucket['tokens'] + $refill
        );

        $bucket['last_refill'] = $currentTime;

        if ($bucket['tokens'] < 1) {
            return response()->json([
                'message' => 'Too many requests.'
            ], 429);
        }

        $bucket['tokens'] -= 1;

        Cache::put($key, $bucket, 60);

        return $next($request);
    }
}
      

Sliding Window Algorithm

Concept

Instead of resetting at fixed intervals, sliding window:

  • Tracks requests over rolling time window
  • Calculates request count in last X seconds dynamically

Example: Limit = 60 per minute. At 10:00:30 → system checks requests from 9:59:30 to 10:00:30.

Implementing Sliding Window in Laravel

We use Redis sorted sets for accurate timestamp tracking.

ip();
        $now = time();

        // Remove old timestamps
        Redis::zremrangebyscore($key, 0, $now - $this->window);

        // Count current requests
        $count = Redis::zcard($key);

        if ($count >= $this->limit) {
            return response()->json([
                'message' => 'Rate limit exceeded.'
            ], 429);
        }

        // Add new request
        Redis::zadd($key, $now, uniqid());
        Redis::expire($key, $this->window);

        return $next($request);
    }
}
      

Using Laravel’s Built-In RateLimiter Properly

Most devs stop here:

Route::middleware('throttle:60,1')->group(function () {
    Route::get('/api/data', [DataController::class, 'index']);
});
    

But Laravel allows advanced logic:

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Request;

public function boot()
{
    RateLimiter::for('api', function (Request $request) {
        if ($request->user()?->isPremium()) {
            return Limit::perMinute(120);
        }
        return Limit::perMinute(60)
            ->by($request->user()?->id ?: $request->ip());
    });
}
    

Real-World Use Cases

1. Login Protection

RateLimiter::for('login', function (Request $request) {
    return Limit::perMinute(5)
        ->by($request->ip());
});
      

Stops brute force attacks.

2. OTP Verification Endpoint

  • 3 attempts per 10 minutes
  • Prevents SMS abuse
  • Saves money

3. Public API SaaS Model

  • Free tier → 1000/day
  • Pro → 10,000/day
  • Enterprise → Custom

Dynamic rate limiting = monetization tool.

4. Preventing Scraping

  • Limit by IP
  • Limit by API key
  • Limit by user agent fingerprint

Scrapers die quickly when you do this properly.

Redis vs Database vs File Cache

If you’re using file cache in production for rate limiting — you’re building a toy.

Use Redis.

  • Atomic increments
  • Distributed systems safe
  • Microsecond precision
  • High concurrency handling

Production stack should be:

Laravel + Redis + Horizon
    

Common Developer Mistakes

  • Only using default throttle
  • Not differentiating premium users
  • Not rate limiting login
  • Not rate limiting expensive endpoints
  • Forgetting distributed systems edge cases
  • Using shared IP logic blindly (NAT problems)

Brutal Reality

If your API can be taken down by:

ab -n 5000 -c 100 http://yourapi.com
    

You're not production-ready.

Rate limiting is not decoration. It’s survival.

Final Thoughts

If you're serious about building scalable Laravel systems:

  • Understand algorithms
  • Choose the correct one
  • Use Redis
  • Customize per user
  • Think monetization + protection

Average developers add throttle:60,1. Serious engineers design traffic control systems.

Now ask yourself honestly — which one are you becoming?

Laravel • Rate Limiting • API Security • Throttling • Web Development

Deepak Dubey

I'm Deepak Dubey, a developer who loves building practical and scalable web solutions. This blog is where I share quick insights, coding tips, and real project experiences in PHP, Laravel, JavaScript, APIs, Python, and more. I created this space to document useful solutions, explore new technologies, and help others facing similar technical challenges. Thanks for visiting — happy learning!

Post a Comment

Feel free to share your thoughts below!
I love hearing from you — your feedback helps me improve!

Previous Post Next Post