On this page

Rate limits

Limit how often each user or IP address calls parts of your API: per table, Auth endpoint, bucket or function, with 429 and Retry-After.

Rate limits stop one user, script or IP address from flooding a part of your API: comments spam, password guessing, an expensive function called in a loop. You set rules in Studio; requests over a rule get 429 Too Many Requests on your project's server, before they reach your database.

#Add a rule

In Studio open API › Rate limits and choose Add rule, or start from a common rule. A rule says what it applies to, how many requests are allowed and how they are counted:

RuleApplies toPathMethodsLimit
10 comments a minute per userDatabase (REST API)commentsPOST10 per minute, per user
5 sign-ins a minute per IPAuthtokenPOST5 per minute, per IP address
3 sign-ups an hour per IPAuthsignupPOST3 per hour, per IP address
Uploads to a bucketStorageobject/avatars/*POST, PUT20 per hour, per user
An expensive functionEdge Functionsgenerate-reportAny5 per minute, per user
RPC functions by nameDatabase (REST API)rpc/send_*POST30 per minute, for the whole project
  • Path is the part after /rest/v1/, /auth/v1/, /storage/v1/ or /functions/v1/. * matches anything. The query string is ignored.
  • Per user counts each signed-in user (the sub of their access token). Calls without a session count per IP address. Per IP address counts each client. For the whole project is one shared budget.
  • Requests with the service_role key are never limited, so your own servers and jobs are not affected.
  • Windows go from one second to one day. Counting is a sliding window, so a client cannot send twice the limit around the turn of a minute.
  • Requests that are refused do not count, so a client that waits for Retry-After gets through.

#What clients receive

http
HTTP/1.1 429 Too Many Requests
Retry-After: 42
X-RateLimit-Limit: 10;w=60
Content-Type: application/json

{"code":"rate_limited","message":"Too many requests (rate limit: Comments per user). Try again in 42 s.","retry_after":42}

The SDK returns this as an error like any other (error.status === 429); show the user a message or retry after Retry-After seconds.

#Try a limit first

Set When the limit is reached to Only record it: requests go through, and the ones that would have been refused appear under Latest refused requests. Switch to refusing once the numbers look right.

#Alerts

Turn on E-mail me when it triggers a lot on a rule to get an e-mail when it refused more than a number of requests in 5 minutes (at most one e-mail per rule every 6 hours). The table shows how many requests each rule allowed and refused since the counters started.

#In SQL

For limits that depend on your data, install the SQL helper (API › Rate limits › In SQL) and call ratelimit.enforce(name, max, per) from a trigger or function. Over the limit it raises an error that the REST API returns as 429 with Retry-After, and the write is rolled back.

SQL
-- At most 10 comments a minute per signed-in user (anonymous callers: per IP)
create function public.comments_rate_limit() returns trigger language plpgsql as $$
begin
  perform ratelimit.enforce('comments', 10, interval '1 minute');
  return new;
end $$;
create trigger comments_rate_limit before insert on public.comments
  for each row execute function public.comments_rate_limit();

-- Your own key: 5 exports an hour per organization
perform ratelimit.enforce('exports', 5, interval '1 hour', new.org_id::text);

Use it in writes (triggers, and functions called with POST): read-only requests cannot record a call. Counts are kept in the unlogged table ratelimit.hits, which is not served by the REST API.

#Limits

LimitFreeProScaleEnterprise
Rate limit rules per project325100500

Rules come on top of your plan's API requests per second and the Auth limits, which always apply. Counters live in memory on your project's server and start again after maintenance.