
December 07, 2025
7 min read
Table of Contents
By Kokil Thapa | Last reviewed: April 2026
Your API is getting hit by 10,000 requests per second from the same IP address, your database is maxed out, and legitimate users are timing out. Without rate limiting, this scenario is not a question of "if" but "when." APIs power everything from mobile apps to SaaS platforms to third-party integrations, and every public endpoint is a target for abuse. As a web developer in Nepal who has built and secured production APIs for clients handling millions of requests, I have implemented rate limiting at every layer — from Laravel middleware to API gateways to Cloudflare edge rules. This guide covers the practical implementation of rate limiting, the algorithms behind it, Laravel-specific strategies, and how to build a layered defense that stops abuse without blocking legitimate traffic.
Quick Answer — What Is API Rate Limiting?
API rate limiting restricts the number of requests a client can make within a time window. For example, 100 requests per minute per API key. It prevents abuse (DDoS, brute force, scraping), protects server resources, ensures fair usage across clients, and maintains API performance under load. Laravel provides built-in throttling middleware, and Redis is the standard backend for tracking request counts at scale.
Why Is Rate Limiting Critical for Modern APIs?
Every API exposed to the internet faces these threats:
- Brute-force attacks — automated attempts to guess passwords, API keys, or authentication tokens
- Credential stuffing — testing stolen username/password combinations from data breaches
- Scraping and data extraction — bots systematically downloading your content, product data, or pricing
- DDoS-like traffic bursts — sudden request spikes that overwhelm server capacity
- Resource exhaustion — expensive endpoints (PDF generation, AI inference, report building) being called repeatedly
- Noisy neighbor abuse — in multi-tenant SaaS systems, one tenant consuming disproportionate API resources
Rate limiting is not just security — it is infrastructure protection. Without it, a single abusive client can degrade service for all your users.
What Are the Main Rate Limiting Algorithms?
Four algorithms power most rate limiting implementations. Each has different trade-offs for accuracy, memory usage, and burst handling.
1. Fixed Window Counter
The simplest approach: count requests in fixed time windows (e.g., per minute). Reset the counter when the window expires.
// Fixed window: 100 requests per minute Window: 14:00:00 - 14:00:59 → Count: 87 (allowed) Window: 14:01:00 - 14:01:59 → Count: 0 (reset)Pros: Simple, low memory usage. Cons: Boundary burst problem — a client can send 100 requests at 14:00:59 and 100 more at 14:01:00, effectively getting 200 requests in 2 seconds.
2. Sliding Window Log
Tracks the timestamp of every request. Counts how many requests fall within the trailing window.
Pros: Accurate, no boundary burst problem. Cons: High memory usage — stores every request timestamp.
3. Sliding Window Counter
A hybrid: combines fixed window counts with a weighted overlap calculation. Used by most production rate limiters including Cloudflare and AWS API Gateway.
Pros: Accurate, low memory. Cons: Slightly more complex implementation.
4. Token Bucket
Each client gets a bucket of tokens that refills at a steady rate. Each request consumes one token. If the bucket is empty, the request is rejected.
// Token bucket: 10 tokens, refill 1 token per second Request at T=0: 10 tokens → 9 tokens (allowed) Request at T=0.1: 9 tokens → 8 tokens (allowed) ... Request at T=1: 1 token + 1 refilled → 1 token (allowed)Pros: Allows controlled bursts, smooth rate limiting. Cons: More state to manage per client. This is the algorithm Laravel's throttle middleware uses internally.
How Do You Implement Rate Limiting in Laravel?
Laravel provides built-in rate limiting through the ThrottleRequests middleware. Here are the practical implementation patterns.
Basic Throttle Middleware
// routes/api.php — 60 requests per minute per IP Route::middleware('throttle:60,1')->group(function () { Route::get('/api/products', [ProductController::class, 'index']); Route::get('/api/products/{id}', [ProductController::class, 'show']); });Named Rate Limiters (Laravel 8+)
// app/Providers/RouteServiceProvider.php RateLimiter::for('api', function (Request $request) { return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip()); }); // Different limits for different endpoints RateLimiter::for('login', function (Request $request) { return Limit::perMinute(5)->by($request->ip()); }); RateLimiter::for('heavy-operations', function (Request $request) { return Limit::perMinute(10)->by($request->user()->id); });Per-User vs Per-IP Rate Limiting
// Per authenticated user — best for API key-based access RateLimiter::for('user-api', function (Request $request) { return $request->user() ? Limit::perMinute(100)->by($request->user()->id) : Limit::perMinute(20)->by($request->ip()); // Stricter for unauthenticated });Tiered Rate Limits by Plan
// Different limits based on subscription plan RateLimiter::for('tiered', function (Request $request) { $user = $request->user(); return match ($user?->plan) { 'enterprise' => Limit::perMinute(1000)->by($user->id), 'business' => Limit::perMinute(300)->by($user->id), 'starter' => Limit::perMinute(60)->by($user->id), default => Limit::perMinute(20)->by($request->ip()), }; });How Should Rate Limit Responses Be Formatted?
When a client exceeds the rate limit, your API must return clear, actionable information. Standard HTTP headers and response codes communicate rate limit status.
Required Response Headers
HTTP/1.1 429 Too Many Requests X-RateLimit-Limit: 60 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 1714500120 Retry-After: 45 { "error": "rate_limit_exceeded", "message": "Too many requests. Please retry after 45 seconds.", "retry_after": 45 }Laravel's throttle middleware adds these headers automatically. Always include Retry-After so well-behaved clients know when to retry.
How Do You Build Layered API Security Beyond Rate Limiting?
Rate limiting alone is not sufficient. Production APIs need multiple security layers.
Layer 1: Edge Protection (Cloudflare / AWS WAF)
Block malicious traffic before it reaches your application. Cloudflare's rate limiting rules can block abusive IPs at the edge, DDoS protection absorbs volumetric attacks, and WAF rules filter known attack patterns (SQL injection, XSS).
Layer 2: API Gateway Rate Limiting
If using AWS API Gateway (with serverless Laravel with Vapor or standalone), configure usage plans with per-key rate limits and burst limits. This provides a second line of defense before requests reach Laravel.
Layer 3: Laravel Application Throttling
The throttle middleware provides per-route, per-user rate limiting with business logic awareness (plan tiers, endpoint sensitivity).
Layer 4: Endpoint-Specific Protection
- Login endpoints — 5 attempts per minute per IP, with exponential backoff on repeated failures
- Password reset — 3 requests per hour per email address
- File upload — 10 uploads per hour per user
- Report generation — 5 requests per hour per user (resource-intensive)
- Search endpoints — higher limits but with result caching to reduce database load
Layer 5: Bot Detection and CAPTCHA
For public-facing endpoints, integrate bot detection (Cloudflare Bot Management, reCAPTCHA v3) to distinguish automated traffic from human users. See our guide on securing your website and server for comprehensive security practices.
How Do You Use Redis for Scalable Rate Limiting?
Laravel's default rate limiter uses the configured cache driver. For production APIs, Redis is the standard because of its atomic operations and sub-millisecond latency.
// .env configuration CACHE_DRIVER=redis REDIS_HOST=127.0.0.1 REDIS_PORT=6379Why Redis?
- Atomic operations — INCR and EXPIRE are atomic, preventing race conditions in concurrent requests
- Sub-millisecond latency — rate limit checks add negligible overhead
- TTL support — keys automatically expire when the rate limit window resets
- Scalability — Redis Cluster supports horizontal scaling for high-traffic APIs
Custom Redis Rate Limiter
// For advanced use cases beyond Laravel's built-in throttle $key = "rate_limit:{$userId}:{$endpoint}"; $limit = 100; $window = 60; // seconds $current = Redis::incr($key); if ($current === 1) { Redis::expire($key, $window); } if ($current > $limit) { abort(429, 'Rate limit exceeded'); }Monitoring and Alerting for Rate Limit Events
Rate limiting is only effective if you monitor it. Set up alerting for:
- High 429 response rates — may indicate an attack or a legitimate client hitting limits too frequently
- Sudden traffic spikes — unusual request patterns that may indicate bot activity
- Per-endpoint abuse patterns — specific endpoints being targeted repeatedly
- Rate limit bypasses — clients rotating IPs or API keys to circumvent limits
Log rate limit events to your monitoring system (Datadog, Grafana, CloudWatch) and set up alerts for thresholds that indicate attack patterns rather than normal usage.
If you need help implementing rate limiting, API security architecture, or abuse prevention for your production APIs, get in touch.

