DEV Community

Atlas Whoff
Atlas Whoff

Posted on

Upstash Redis for Serverless: Rate Limiting and Caching at the Edge

Upstash Redis for Serverless: Rate Limiting and Caching at the Edge

Traditional Redis requires a persistent connection — incompatible with serverless functions that cold-start on every request. Upstash provides HTTP-based Redis that works anywhere, including Edge Runtime.

Why Upstash

  • HTTP API — no connection pooling, works in Edge/serverless
  • Per-request pricing — pay for what you use
  • Global replication — low latency worldwide
  • Free tier: 10k commands/day

Install

npm install @upstash/redis @upstash/ratelimit
Enter fullscreen mode Exit fullscreen mode

Basic Usage

import { Redis } from '@upstash/redis';

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_REST_URL!,
  token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});

// Cache an API response
async function getCachedData(key: string) {
  const cached = await redis.get(key);
  if (cached) return cached;

  const data = await fetchExpensiveData();
  await redis.setex(key, 3600, JSON.stringify(data)); // TTL: 1 hour
  return data;
}
Enter fullscreen mode Exit fullscreen mode

Rate Limiting

import { Ratelimit } from '@upstash/ratelimit';

const ratelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(10, '10 s'), // 10 req per 10s
  analytics: true,
});

// In Next.js middleware or API route
export async function middleware(request: NextRequest) {
  const ip = request.ip ?? '127.0.0.1';
  const { success, limit, remaining, reset } = await ratelimit.limit(ip);

  if (!success) {
    return NextResponse.json(
      { error: 'Rate limit exceeded' },
      {
        status: 429,
        headers: {
          'X-RateLimit-Limit': limit.toString(),
          'X-RateLimit-Remaining': remaining.toString(),
          'X-RateLimit-Reset': reset.toString(),
        }
      }
    );
  }
  return NextResponse.next();
}

export const config = { matcher: '/api/:path*' };
Enter fullscreen mode Exit fullscreen mode

Session Storage

// Store session data without a database
async function createSession(userId: string): Promise<string> {
  const sessionId = crypto.randomUUID();
  await redis.setex(
    `session:${sessionId}`,
    86400, // 24 hours
    JSON.stringify({ userId, createdAt: Date.now() })
  );
  return sessionId;
}

async function getSession(sessionId: string) {
  const data = await redis.get(`session:${sessionId}`);
  return data ? JSON.parse(data as string) : null;
}
Enter fullscreen mode Exit fullscreen mode

Distributed Locks

// Prevent duplicate processing (e.g. webhook deduplication)
async function processOnce(eventId: string, fn: () => Promise<void>) {
  const key = `processed:${eventId}`;
  const acquired = await redis.set(key, '1', { nx: true, ex: 3600 });
  if (!acquired) return; // Already processed
  await fn();
}
Enter fullscreen mode Exit fullscreen mode

Leaderboard

// Sorted sets for rankings
await redis.zadd('leaderboard', { score: 1500, member: 'user:123' });
const top10 = await redis.zrange('leaderboard', 0, 9, { rev: true, withScores: true });
Enter fullscreen mode Exit fullscreen mode

Upstash Redis is pre-configured in the AI SaaS Starter Kit — rate limiting middleware, session caching, and API response cache all wired up. $99 one-time at whoffagents.com.

Top comments (0)