Rate Limiting Next.js API Routes using Cloudflare

By Thomas Wang / @thomaswang
Updated on January 29, 2023

Next.js API Routes are a powerful feature of Next.js, and you can effectively design and run your entire REST API from them. However, I run Next.js on Vercel, and unfortunately they do not provide a first party solution for rate limiting (I asked for one in GitHub Discussions).

Vercel recommends their Upstash integration, but I found the Upstash console confusing and having to use Redis just for this one feature seemed to be overkill. On the other hand, Cloudflare is primarily a cloud security platform and rate limiting is something they have robust solutions for and a comprehensive article on.

I attempted the following before landing on this solution:

  • Upstash’s solution
  • lru-cache solution
  • Kitty’s solution
Notice: A previous version of this post used Next.js Middleware and a Cloudflare Service Worker. This was a mistake as Cloudflare is designed to act as a proxy between the user and your origin.

Follow these 3 steps to use Cloudflare to rate limit your API Routes:

Step 1: Use Cloudflare With Proxy Enabled

First open the Cloudflare dashboard and select your website / domain.

Go to DNS → Records.

Make sure Proxy status is turned on.

Go to SSL/TLS → Overview.

Make sure SSL/TLS encryption mode is set to Full.

Step 2: Set Up Page Rule for Vercel Domain Verification Checks

Go to Rules → Page Rules → Create Page Rule

For your URL use *<YOUR_DOMAIN>/.well-known/acme-challenge/*. Use the first asterisk * wildcard to match all your subdomains. Pick the SSL setting and select Off. Vercel needs this path whitelisted to do domain verification checks.

Step 3: Set up Rate Limiting on Domain / Website

Go to Security → WAF → Rate Limiting rules → Create rule

Create a rate limiting rule that checks if the incoming request path starts with /api with your desired rate limit (e.g. 10 requests / 10 seconds).

See it in Action

If you hit https://thomas.wang/api more than 10 times in 10 seconds and you’ll get:

HTTP/1.1 429 Too Many Requests
Date: Sat, 28 Jan 2023 23:41:15 GMT
Content-Type: text/plain; charset=UTF-8
Content-Length: 16
Connection: close
Retry-After: 9
X-Frame-Options: SAMEORIGIN
Referrer-Policy: same-origin
Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Report-To: {"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v3?s=P5oxpN13lxERhT8b110mjwqdHvnazEtWVbwLNNmotg%2F4X%2FV%2FsGf8YRkGhd3YyVNwQjDlD%2FMiEqZzioygfQBovZ7QY8dap8fSj19g54dmmUHFz4ZE9kelL3QL3JnVJw%3D%3D"}],"group":"cf-nel","max_age":604800}
NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Strict-Transport-Security: max-age=15552000; includeSubDomains; preload
X-Content-Type-Options: nosniff
Server: cloudflare
CF-RAY: 790d93e96ee02ec1-LAX
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
 
error code: 1015

Additional Resources

  • vercel.com/guides/using-cloudflare-with-vercel
  • developers.cloudflare.com/waf/rate-limiting-rules
ReplyCommentSubmitWriting
Writing