liveBook · Manning

Rate limit

As explained in Build AI-Enhanced Web Apps

Throttling is the deliberate reduction or control of request processing or resource consumption to prevent overload.

Rate limiting caps how many requests a client can make within a specified time. Put it in front of an AI API to reduce abuse, protect backend capacity, and control spending on external models. Provider limits are separate: an application must also keep its outbound requests within the provider’s allowance. section 9.3.2 section 8.2.2

A practical implementation has three parts:

  • Run the check early in the request-processing pipeline, before core application logic. It can be composed with CORS handling, authentication, and security headers. section 9.1.2
  • Track requests against a client identifier in Redis. One Upstash example uses a sliding window of five requests per ten seconds. section 9.3.2
  • When the limit is exceeded, stop processing and return HTTP 429 with a “Too many requests” message. Test the behavior by generating load against the endpoint. section 9.3.2
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 configures @upstash/ratelimit with Upstash Redis, checks an identifier derived from the request IP, and stops the chain with a 429 response when the check fails. section 9.3.2

A request-rate limit and a message quota serve related but different jobs. For an authenticated /api/chat route, a daily quota can use a Clerk user ID and a date-stamped Redis counter. The illustrated route increments the counter, rejects messages after ten for that dated key, and expires a newly created key after 24 hours. Enforce this on the backend rather than relying on the interface. section 9.3.2

Listing 9.6 Integrating message quota limits
import { getAuth } from '@clerk/nextjs/server';    #1
const checkMessageQuota = async (userId) => {
  const now = new Date();
  const today = now.toISOString().split('T')[0];
  const key = `message_count:${userId}:${today}`;    #2

  const count = await redis.incr(key);    #3
  if (count === 1) {
    await redis.expire(key, 24 * 60 * 60);
  }

  if (count > 10) {    #4
    return false;
  }

  return true;
};

export async function POST(req) {
  try {
    // rest of the code
const { userId } = getAuth(req);
    const quotaAvailable = await checkMessageQuota(userId);
    if (!quotaAvailable) {    #5
      return new Response(JSON.stringify(
{ error: 'Message quota exceeded. 
You can only send 10 messages per day.' }), {
        status: 429,
        headers: {
          'Content-Type': 'application/json',
        },
      });
    }
// rest of the code
}

The route listing shows the user-specific counter, expiry, ten-message threshold, and 429 quota response. section 9.3.2

For public production endpoints, consider an external control such as Cloudflare, AWS WAF, or a dedicated Redis cluster so abusive traffic can be stopped before it consumes application-server resources. Rate limiting remains one layer alongside authentication, input validation, and other security controls; document-upload endpoints are another candidate for limits and quotas. section 9.3.2 section 11.2.2

How Build AI-Enhanced Web Apps covers it

How deep it goes
Works through Redis-backed middleware and a separate authenticated message quota, including thresholds, counters, expiry, 429 responses, and load testing.
Examples
Uses a five-request sliding window, a load-test script, and a ten-message daily quota on /api/chat.
What it assumes
Assumes familiarity with Next.js API routes, server-side code, AI workflows, LangChain.js, and the Vercel AI SDK.
What you can do after
Apply it via @upstash/ratelimit and Upstash Redis to reject excess requests, then test the limit under load.
How it connects
Connects security middleware, authentication, Redis, message quotas, and external AI-provider limits.

Also explained in

Compare how 14 books explain rate limit →

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.