liveBook · Manning

Upstash Redis

As explained in Build AI-Enhanced Web Apps

Upstash Redis is a hosted Redis-compatible data store provided as a low-latency serverless service.

Upstash Redis is a hosted, low-latency Redis-compatible store for application data that must be available across requests. In a Next.js AI application, it can hold rate-limit state, message counts, interview sessions, and cached feedback. It serves a different role from Upstash Vector, which stores embeddings for similarity search. section 9.3.2 section 10.1.3 section 11.1.3

Three practical patterns show how the store fits into request handling:

  • Rate limits: create a Redis client with UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN, then pass it to @upstash/ratelimit. A sliding window allows five requests per ten seconds per IP address; rejected requests receive HTTP 429. section 9.3.2
  • Message quotas: in the chat API route, use a Clerk user ID and UTC date to form message_count:${userId}:${today}. Increment the count, set a 24-hour expiry on its first increment, and reject counts above ten with HTTP 429. section 9.3.2
  • Interview state: associate users with session IDs in a Redis set, retrieve session data from hashes, and cache generated feedback under feedback:${sessionId}. Store conversation history and user settings so past threads can be reopened. section 10.1.3 section 10.3.1
Listing 9.5 Integrating a rate limiter in middleware
import { Ratelimit } from "@upstash/ratelimit";    #1
import { Redis } from "@upstash/redis";

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

const ratelimit = new Ratelimit({    #3
  redis: redis,
  limiter: Ratelimit.slidingWindow(5, "10 s")
});


const rateLimit = async (request, response) => {
  const identifier = request.ip || '127.0.0.1';    #4

  try {
    const { success, limit, reset, remaining } = 
await ratelimit.limit(identifier);    #5

    if (!success) {
      console.log("Rate limit exceeded");
      return {
        response: NextResponse.json(
{ message: "Too many requests" }, { status: 429 }),
        continue: false,
      };
    }

    return { continue: true };

  } catch (error) {
    console.error("Rate limiting error:", error);
    return {
      response: NextResponse.json(
{ error: "Internal Server Error" }, { status: 500 }),
      continue: false,
    };
  }
};

The middleware listing connects environment-based Redis credentials to a sliding-window limiter and shows where a request is allowed or rejected. section 9.3.2

Listing 10.1 Function to retrieve all the past interview sessions
export async function fetchInterviewSessions(userId) {
  const sessionIds = 
await redis.smembers(`user:sessions:${userId}`);    #1
  const sessions = await Promise.all(
    sessionIds.map(async (sessionId) => {    #2
      const session = await redis.hgetall(`session:${sessionId}`);
      return { ...session, id: sessionId };
    }),
  );
  sessions.sort((a, b) => b.createdAt - a.createdAt);    #3
  return sessions;
}

The session retrieval function shows the data model in use: read a user's set of session IDs, fetch each session hash, and sort the results. section 10.1.3

Keep the storage choice proportional to the data model. Simple session-to-message pairings can be maintained in Redis, but complex relationships favor SQL and its persistence-layer transactions. For hostile traffic, consider a rate-limiting service that blocks requests before they consume application-server resources. section 10.3.1 section 9.3.2

How Build AI-Enhanced Web Apps covers it

How deep it goes
Works through Redis-backed middleware, quota keys, and session retrieval, but does not examine Redis internals.
Examples
Uses a five-request sliding window, a ten-message daily quota, and an interview-session lookup using Redis sets and hashes.
What it assumes
Assumes JavaScript and Next.js request-handling familiarity; supplies concrete Redis keys and calls rather than teaching Redis from zero.
What you can do after
Apply it via @upstash/redis and @upstash/ratelimit to enforce request limits and persist application-specific state.
How it connects
Connects Redis to Next.js API routes, Clerk authentication, the Vercel AI SDK, rate limiting, and SQL persistence trade-offs.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Build AI-Enhanced Web Apps. The section links point to the parts of the book it draws on.