This error occurs when your application makes too many requests to Supabase Auth or Management API within a short timeframe, triggering built-in rate limiting that returns a 429 status code.
The "over_request_rate_limit" error is Supabase's way of protecting its services from abuse and ensuring system stability. When your application exceeds the allowed number of requests per time window, Supabase temporarily blocks additional requests and returns this error with an HTTP 429 (Too Many Requests) status code. Supabase implements rate limiting at multiple levels: the Management API allows up to 10 requests per minute with a maximum of 1 request per second to prevent burst traffic. The Auth API has endpoint-specific limits that are configurable per project. The Data API (PostgREST) limits to 100 requests per IP address within 5 minutes. These limits are designed to prevent single users or applications from overwhelming shared resources. Rate limit information is provided in response headers: X-RateLimit-Limit shows the maximum allowed requests, X-RateLimit-Remaining indicates how many requests you have left, and X-RateLimit-Reset tells you when the limit window resets (in milliseconds). Understanding these headers is crucial for implementing proper retry logic and request throttling.
Inspect the response headers from your failed requests to understand your current rate limit status:
const { data, error } = await supabase.auth.signUp({
email: '[email protected]',
password: 'password'
});
// Access response headers (implementation varies by HTTP client)
// Look for:
// X-RateLimit-Limit: 10
// X-RateLimit-Remaining: 0
// X-RateLimit-Reset: 1234567890Check the Supabase dashboard under Project Settings → Logs → Auth/API to see which endpoints are being called most frequently.
Add retry logic with increasing delays when you receive rate limit errors:
async function retryWithBackoff(fn, maxRetries = 3, initialDelay = 1000) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429 && i < maxRetries - 1) {
const delay = initialDelay * Math.pow(2, i);
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
}
// Usage
const result = await retryWithBackoff(async () => {
const { data, error } = await supabase.auth.signIn({
email, password
});
if (error) throw error;
return data;
});This approach respects the rate limit by waiting before retrying, with increasingly longer delays.
Audit your application to eliminate redundant or excessive API calls:
// BAD: Calling getSession on every render
useEffect(() => {
supabase.auth.getSession(); // Runs too often
}, []);
// GOOD: Cache session and only refresh when needed
const [session, setSession] = useState(null);
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session);
});
// Listen for auth changes instead of polling
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => setSession(session)
);
return () => subscription.unsubscribe();
}, []); // Run once on mountReplace polling patterns with event listeners or webhooks where possible.
Use throttling or debouncing to limit request frequency:
import { throttle } from 'lodash';
// Throttle search requests to max 1 per second
const throttledSearch = throttle(async (query) => {
const { data, error } = await supabase
.from('items')
.select('*')
.ilike('name', `%${query}%`);
return data;
}, 1000, { leading: true, trailing: false });
// Use in component
const handleSearchChange = (e) => {
throttledSearch(e.target.value);
};For batch operations, add delays between chunks of requests.
Adjust rate limits for your specific needs in the Supabase dashboard:
1. Go to Project Settings → Authentication → Rate Limits
2. Review the default limits for each auth endpoint
3. Increase limits for endpoints you use heavily (requires paid plan)
4. Configure per-IP vs global rate limiting based on your use case
Note: Free tier has fixed rate limits. Pro and above plans allow customization.
If hitting email rate limits for auth emails (password reset, signup confirmations):
1. Go to Project Settings → Authentication → SMTP Settings
2. Configure your own SMTP provider (SendGrid, Mailgun, AWS SES, etc.)
3. Set higher sending limits appropriate for your provider
4. Update rate limit settings in Authentication → Rate Limits
# Example environment variables for custom SMTP
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USER=apikey
SMTP_PASS=your_sendgrid_api_key
[email protected]This removes dependency on Supabase's built-in email limits.
For server-side applications, implement proper connection and request management:
// Create a request queue with concurrency limit
class RequestQueue {
constructor(maxConcurrent = 5) {
this.maxConcurrent = maxConcurrent;
this.running = 0;
this.queue = [];
}
async add(fn) {
while (this.running >= this.maxConcurrent) {
await new Promise(resolve => this.queue.push(resolve));
}
this.running++;
try {
return await fn();
} finally {
this.running--;
const resolve = this.queue.shift();
if (resolve) resolve();
}
}
}
const queue = new RequestQueue(3); // Max 3 concurrent requests
// Usage
const results = await Promise.all(
userIds.map(id =>
queue.add(() => supabase.auth.admin.getUserById(id))
)
);This ensures you never exceed safe concurrency levels.
For applications with unpredictable traffic spikes, consider implementing a Redis-based distributed rate limiter that works across multiple application instances. This allows you to enforce rate limits before requests even reach Supabase, saving on quota and reducing errors.
If you're on the Pro plan or higher, you can request increased rate limits by contacting Supabase support with details about your use case and expected traffic patterns. They can often accommodate legitimate high-traffic applications.
For local development environments, if you encounter persistent rate limit errors, try stopping and restarting your local Supabase instance with supabase stop followed by supabase start. This resets local rate limit counters.
When implementing rate limit handling, be aware that the Management API has both a per-minute limit (10 requests) AND a per-second limit (1 request) to prevent burst traffic. Your retry logic should account for both constraints.
For production applications, monitor your rate limit usage proactively using the X-RateLimit-Remaining header. Set up alerts when you're consistently using >80% of your quota to catch issues before they impact users.
email_conflict_identity_not_deletable: Cannot delete identity because of email conflict
How to fix "Cannot delete identity because of email conflict" in Supabase
mfa_challenge_expired: MFA challenge has expired
How to fix "mfa_challenge_expired: MFA challenge has expired" in Supabase
conflict: Database conflict, usually related to concurrent requests
How to fix "database conflict usually related to concurrent requests" in Supabase
phone_exists: Phone number already exists
How to fix "phone_exists" in Supabase
StorageApiError: resource_already_exists
StorageApiError: Resource already exists