A client in Abu Dhabi called at 10 PM last summer, frantic. Their Next.js API endpoint for validating discount codes was getting hammered by bots – 15,000 requests in 10 minutes. The app was down, their promo campaign was burning budget, and customers couldn’t checkout. We’d built-in basic rate limiting during development, but it couldn’t handle sustained abuse. Three cups of coffee later, we switched from memory store to Redis with tighter thresholds, and the flood stopped. I walked away with one lesson: production-grade rate limiting isn’t optional, it’s a survival skill.
How Rate Limiting Actually Works in Real Projects
When I started web dev in 2016, rate limiting meant slapping an ->throttle(60) in a Laravel RouteServiceProvider and forgetting it. But real clients (especially UAE fintechs and e-commerce platforms) need more precision. Here’s what I’ve learned:
- •Bots ≠ Humans: A real person won’t send 50 POST requests per second. Set thresholds based on what’s normal for your business
- •IP is leaky: In GCC countries, ISP NAT means shared IPs. Don’t block based solely on IP when serving mobile users on telco networks
- •Redis is your friend: Both Laravel and Next.js work fine with memory stores, but those don't scale across containers or instances. We moved one limo booking platform from
MemoryStoretoRedisStoreafter a single DDOS test blew past the limit
I use different identifiers depending on context:
// Next.js middleware example
export function getClientKey(req: NextRequest) {
const header = req.headers.get('X-API-Key')
return header ? `api-${header}` : `ip-${req.ip}`
}Laravel’s Built-In Tools vs Custom Middleware
Laravel’s throttle:api middleware is great for simple rate limiting, but it’s too blunt for production apps. On a real estate platform (Reach Home Properties), we had to handle three types of clients:
- Regular users via mobile app (React Native)
- Agent portals (Next.js)
- Third-party APIs (internal systems)
We ended up writing a custom middleware using laravel-redis:
RateLimiter::for('api', function (Request $request) {
return Limit::perMinute(50)->by(
$request->user() ? 'user-'.$request->user()->id : $request->ip()
)->response(function () {
return response('Too many requests.', 429);
});
});But here’s the catch: On a logistics client’s app in Dubai, using request->ip() caused false positives when drivers were on 4G networks – their IPs changed mid-shift due to telco NAT. We switched to requiring API keys for rate limiting on field operations APIs, even though it added 2 days to the sprint.
// RouteServiceProvider.php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
// Later added this for API routes
Limit::perMinute(300)->by(fn (Request $request) =>
Str::lower($request->user()->email) ?: $request->ip()
);Implementing Rate Limiting in Next.js
Next.js doesn’t have built-in rate limiting, but you can implement it in API routes or middleware. I prefer middleware for global protection. For a luxury car booking app (Tawasul Limo), we combined rate limiting with NextAuth to handle both guests and logged-in users:
// middleware.ts
export async function rateLimit(req: NextRequest) {
const clientKey = getClientKey(req) // from earlier
const redis = new Redis()
const key = `rate_limit:${clientKey}`
const current = await redis.incr(key)
if (current === 1) {
await redis.expire(key, 60) // 60 seconds
}
if (current > 150) { // 150 reqs/minute
return NextResponse.json({ error: 'Too many requests' }, { status: 429 })
}
}Yes, this means you need Redis setup. I’ve wasted 8 hours trying to make a memory store work in a Vercel serverless environment – don’t do it. Dockerizing with Redis is faster than fighting platform limits.
For Next.js apps in production, I always pair this with:
- •Docker for Next.js and Laravel: My Local Dev Setup That Actually Works
- •API gateways like Cloudflare rate limiting as a second defense layer
Balancing Performance and Security
In a mobile-focused market like UAE, where 4G dropouts are common and users might resubmit payments, you can’t just slap hard limits everywhere. I learned this the hard way deploying an AI-powered plant care app (Greeny Corner) where users submitted photos for disease analysis. The image processing took 5 seconds per request, and our initial rate limiting config:
// Initial bad config
if (requests > 10 per minute) blockThis caused users to double-tap requests when the app felt "slow", creating a feedback loop that crashed the backend.
The fix? Weighted rate limiting:
// Better version with Redis & weighted costs
// API clients get different costs based on workload
const cost = req.body.isHighPriority ? 2 : 1
const current = await redis.incrby(`usage:${key}`, cost)
// 20 points per minute max
if (current > 20) denyIt’s more maintenance, but necessary for APIs with variable workload per request.
Frequently Asked Questions
How to rate limit authenticated vs unauthenticated API users in Laravel?
Use different identifiers in your rate limiter. For unauthenticated users, fall back to IP. For authenticated users, use their unique ID:
// RouteServiceProvider.php
Limit::perMinute(200)->by(fn ($request) =>
$request->user()?->id ?: $request->ip()
)Can I use API gateways like Cloudflare for rate limiting?
Absolutely. For a corporate site with Laravel/Next.js backend (DAS Holding), we combined Cloudflare rate rules that block at 1,000 RPS with Laravel’s finer-grained limits. Just be careful with caching – Cloudflare may cache 429 responses longer than you expect.
How do I test rate limiters in production?
Never just guess. For one client with daily flash sales, we wrote a load test using Artillery:
# artillery.yaml
config:
target: "https://api.yoursite.com/endpoint"
phases:
- duration: 60
arrivalRate: 30Run this from both UAE and EU locations to catch regional behavior differences.
Should rate limiting be done at the database level?
No. For high-traffic APIs on MySQL, you’ll introduce bottlenecks. We moved one logistics client from database counters to Redis after seeing their database CPU hit 100% during stress tests. Use Redis with proper TTLs and fallback mechanisms.
Work With Me on Your Next Project
I’ve spent 7+ years battling real-world API abuse across 40+ projects for UAE and GCC businesses. If your startup, enterprise, or government contractor needs a security review – or if you’re stuck implementing rate limiting in Next.js/Laravel – my team and I can help. Book a free consultation to walk through your specific scenario. You’ll get concrete solutions, not PowerPoints.