Adding Rate Limit to nuxt.config.js - Example

15 replies
Last updated: Jul 20, 2022
Hi, hoping someone can help me with our API limits. We have a team membership and therefore have plenty of api request allowance. However, because we use Nuxt to generate our sites staticly, the IP (Netlify) that hits sanity is always the same, and so we are having build errors saying "ClientError: API rate limit exceeded". Can we not just have an api limit overall? We are having to tell our client they can't deploy changes because the api limit has been hit, and yet they are paying for the higher tier?
Please can someone let me know how we can get around this asap as they are obviously not happy about it! cc
user J

It would be really nice to be able to give sanity an allowed IP address, that doesn't have any extra limits placed on it.

On this note, please can someone explain to me when my API limit from a single IP resets? The docs just say 'until the period ends' which isn't very informative!
AI Update

I totally understand your frustration! This is a common pain point for teams using static site generators like Nuxt with build services like Netlify. Let me break down what's happening and provide solutions that actually work.

What's Happening

According to the technical limits documentation, Sanity enforces rate limits per client IP address per second:

  • Maximum global API call rate: 500 requests/second per IP
  • Maximum mutation rate: 25 req/s per IP
  • Maximum upload rate: 25 req/s per IP

When Nuxt generates your site statically, all requests come from Netlify's build server (single IP), and if you exceed 500 req/s, you get the 429 ClientError: API rate limit exceeded.

To answer your specific question about when the limit resets: it's per second. If you hit 500 requests in one second, you'll get rate limited for the remainder of that second. Once the next second begins, you get another 500 requests. So "until the period ends" means until the current one-second window completes.

Your team plan's monthly API allowance is separate from this per-second rate limit - both exist independently. You have plenty of monthly quota, but you need to spread requests out during builds to avoid bursting past 500 req/s.

Solutions

1. Use the API CDN (Most Important!)

The API CDN has unlimited rate for cached responses. Make sure your Sanity client is configured to use it:

import {createClient} from '@sanity/client'

const client = createClient({
  // ... your config
  useCdn: true, // Enable CDN - unlimited cached requests!
  apiVersion: '2025-05-16'
})

On subsequent builds, most content will be served from the CDN without hitting rate limits. This is the biggest win for static generation.

2. Control Parallelism in Your Data Fetching

Limit how many concurrent requests your build makes. You can use a concurrency helper:

// Helper to limit concurrent promises
async function pLimit(tasks, limit) {
  const results = []
  for (let i = 0; i < tasks.length; i += limit) {
    const batch = tasks.slice(i, i + limit)
    results.push(...await Promise.all(batch))
  }
  return results
}

// In your prerender logic
const slugs = ['page-1', 'page-2', /* ... */]
const fetchTasks = slugs.map(slug => 
  () => client.fetch(`*[slug.current == $slug][0]`, {slug})
)

// Fetch 10 at a time instead of all at once
const pages = await pLimit(fetchTasks.map(fn => fn()), 10)

You can also use libraries like p-limit for more sophisticated concurrency control. Start with a low number (10-20) and gradually increase until you find the sweet spot.

3. Batch Your GROQ Queries

Instead of fetching each page individually, batch queries to reduce total request count:

// Instead of one query per page (100 pages = 100 requests)
const pages = await Promise.all(
  slugs.map(slug => client.fetch(`*[slug.current == $slug][0]`, {slug}))
)

// Batch into a single query (100 pages = 1 request)
const pages = await client.fetch(
  `*[_type == "page" && slug.current in $slugs]`,
  {slugs: allSlugs}
)

4. Use Incremental Static Regeneration

Instead of rebuilding everything on each deploy, use Nuxt's ISR capabilities:

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/blog/**': { isr: 3600 }, // Regenerate blog posts every hour
    '/': { prerender: true }
  }
})

This way you're only rebuilding changed pages, dramatically reducing API requests per build.

5. Add Delays Between Sequential Requests

If you're making many sequential calls, add a small delay:

async function fetchWithDelay(query, params, delayMs = 50) {
  await new Promise(resolve => setTimeout(resolve, delayMs))
  return client.fetch(query, params)
}

About IP Whitelisting

Unfortunately, Sanity doesn't currently offer IP whitelisting to bypass rate limits. The per-second rate limits protect the platform for all users, even on paid plans. However, the 500 req/s limit is quite generous - the issue is the burst nature of static builds hitting it all at once.

Immediate Action Plan

  1. Verify useCdn: true in your Sanity client config - this is the biggest fix
  2. Implement request batching where possible to reduce total requests
  3. Add concurrency control to your data fetching code (limit to 10-20 parallel requests)
  4. Consider ISR instead of full rebuilds for frequently changing content

The combination of CDN caching (unlimited rate) and spreading out uncached requests should resolve your build failures. Once you have CDN caching working properly, subsequent builds will be much faster and won't hit rate limits nearly as often.

Let me know if you need help implementing any of these solutions!

Hey
user L
! It's important to clarify that these are two separate things. API request quota varies depending on the plan you have, but the rate limit is the rate at which you can execute concurrent API requests. That will never change. You'll need to limit your requests to 25/second.
Thanks for getting back to me
user M
! Oh I see, okay I didn't know that! Do you have any idea how I can add a delay to my calls in when building the site statically with nuxt?
I do! I usually use this package to create a queue of my changes. That way I can execute the code I need in a single script.
Cc
user J
user M
thank you so much, I will try it first thing tomorrow!
Wasnt the issue that Ash was saying though about the fact it was one complex query
user L
in which case would this resolve it?
user J
Ash just informed me you've been discussing this via DM. If this is happening during the actual build that's something else entirely.
Doh! - yes it is but thank you for your help
any ideas gratefully received
This part is unfortunately outside my realm of knowledge, but we will discuss internally to help find solution!
Thank you
user M
!
Please let us know, as we have clients waiting on us!
We have solved this - just in case its helpful to anyone else!
In
nuxt.config.js
, add
generate: {
concurrency: 250, //only build 250 at a time based on the api rate limit
interval: 100, //delay by 0.1s
}
You can fiddle with those numbers, but thats what I have found works for me!
Thanks
user L
for sharing the solution here!
Thank you for sharing
user L
!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?