Rate Limiting

Protect your API endpoints with rate limiting. Easy to set up and customize for different usage patterns.

The boilerplate includes a robust rate limiting system using Upstash Redis, with flexibility to switch to other storage solutions like DynamoDB or AWS ElastiCache.

Note: The boilerplate comes with rate limiting pre-configured for critical endpoints like authentication and API calls - just modify the limits to match your needs!

What's Included

The rate limiting system provides:

  • Pre-configured Upstash Redis integration
  • Built-in tRPC middleware for easy implementation
  • Flexible rate limit configurations
  • Custom error messages

Setting Up Upstash Redis

  1. Create an Upstash account at upstash.com
  2. Create a Redis database
  3. Copy your credentials to your .env file:
    UPSTASH_REDIS_REST_URL=https://xxxxxxxxxxxxxxxxxxx.upstash.io
    UPSTASH_REDIS_REST_TOKEN=AcCdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    

Implementation

Rate limiting is available in all tRPC procedures through the context:

export const publicProcedure = t.procedure.use(async (opts) => {
  return opts.next({
    ctx: {
      ...opts.ctx,
      rateLimit: async (limits: RateLimitConfig[]) => {
        if (!limits.length) return;
        const results = await Promise.all(
          limits.map((limit) => checkRateLimit(limit))
        );
        const failedLimit = results.find((result) => !result.success);
        if (failedLimit) {
          throw new TRPCError({
            code: "TOO_MANY_REQUESTS",
            message: failedLimit.errorMessage || 
              "Too many requests. Please try again later.",
          });
        }
        return results;
      },
    },
  });
});

Usage Example

Apply rate limiting to any tRPC procedure:

forgotPassword: publicProcedure
  .input(
    z.object({
      email: z.string().email("Invalid email address"),
    }),
  )
  .mutation(async ({ input, ctx: { rateLimit, ip } }) => {
    await rateLimit([
      {
        id: ip,
        windowSeconds: 24 * 60 * 60,  // 24 hours
        maxRequests: 5,
        errorMessage: "Too many password reset requests. Please try again tomorrow.",
      },
    ]);
    // ... handle password reset
  }),

Key Features

  1. Multiple Limits: Apply several rate limits to a single endpoint
  2. Custom Messages: Define specific error messages for each limit
  3. Storage Agnostic: Easy to switch between Redis providers

Need Help?

Best Practices

  1. Set appropriate window sizes for different actions
  2. Consider both per-user and per-IP limits
  3. Monitor rate limit hits in production