Rate Limiting Implementation
Implement rate limiting for API endpoints using database-backed usage tracking. Restrict requests per user over a specified time period.
Sby Skills Guide Bot
DevOpsIntermediate0 views0 installs3/3/2026Claude CodeCursorCopilot
api-rate-limitingusage-trackingquota-managementnextjsdrizzle-orm
name: rate-limit-setup description: Implement rate limiting for API endpoints. Use when user mentions "rate limit", "quota", "usage tracking", "throttle", or "limit requests".
Rate Limiting Implementation
This project uses database-backed rate limiting via the usage_tracking table.
Current Implementation
Located in app/api/generate-image/route.ts:
- Limit: 2 premium images per user per 24 hours
- Identification: SHA-256 hash of IP + User-Agent (anonymous)
- Reset: Automatic after 24 hours
Instructions
- Create user identifier (anonymous hash):
const getUserIdentifier = async (req: NextRequest): Promise<string> => {
const ip = req.headers.get('x-forwarded-for')?.split(',')[0]
|| req.headers.get('x-real-ip')
|| 'unknown';
const userAgent = req.headers.get('user-agent') || 'unknown';
const encoder = new TextEncoder();
const data = encoder.encode(ip + userAgent);
const hashBuffer = await crypto.subtle.digest('SHA-256', data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
};
- Check and update usage:
import { db, usageTracking } from '@/db';
import { eq } from 'drizzle-orm';
const checkUsage = async (identifier: string, limit: number) => {
const existing = await db
.select()
.from(usageTracking)
.where(eq(usageTracking.userIdentifier, identifier))
.limit(1);
let usage = existing[0] || null;
const now = new Date();
const resetNeeded = !usage ||
now.getTime() - new Date(usage.lastResetAt!).getTime() > 24 * 60 * 60 * 1000;
if (!usage) {
const [inserted] = await db
.insert(usageTracking)
.values({ userIdentifier: identifier, premiumImagesCount: 0, lastResetAt: now })
.returning();
usage = inserted;
} else if (resetNeeded) {
const [updated] = await db
.update(usageTracking)
.set({ premiumImagesCount: 0, lastResetAt: now, updatedAt: now })
.where(eq(usageTracking.userIdentifier, identifier))
.returning();
usage = updated;
}
const withinLimit = (usage?.premiumImagesCount || 0) < limit;
return { withinLimit, usage };
};
- Increment counter after successful action:
await db
.update(usageTracking)
.set({
premiumImagesCount: (usage?.premiumImagesCount || 0) + 1,
updatedAt: new Date(),
})
.where(eq(usageTracking.userIdentifier, userIdentifier));
- Return appropriate response when limited:
if (!withinLimit) {
return NextResponse.json(
{ error: 'Rate limit exceeded. Try again in 24 hours.' },
{ status: 429, headers: corsHeaders }
);
}
For New Rate-Limited Features
If tracking a different resource, add a new column to usage_tracking or create a new table:
// In db/schema.ts
featureCount: integer('feature_count').default(0),
Examples
- "Limit roasts to 5 per day" → Add
roastCountcolumn, apply pattern above - "Add API request throttling" → Create new tracking table for general requests
Guardrails
- Never expose user identifiers in responses
- Log usage counts, not full hashes
- Use 429 status code for rate limit responses
- Include reset time info in rate limit responses when possible
- Test reset logic carefully (24-hour boundary)
Related skills
Docker Compose Architect
100
Designs optimized Docker Compose configurations.
Claude CodeCopilotadvanced
4301561271Admin
Incident Postmortem Writer
100
Writes structured and blameless incident postmortem reports.
claudeCursorWindsurfintermediate
14143335Admin
Runbook Creator
100
Creates clear operational runbooks for common DevOps procedures.
claudeCursorWindsurfintermediate
10832261Admin