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:
| Rule | Applies to | Path | Methods | Limit |
|---|---|---|---|---|
| 10 comments a minute per user | Database (REST API) | comments | POST | 10 per minute, per user |
| 5 sign-ins a minute per IP | Auth | token | POST | 5 per minute, per IP address |
| 3 sign-ups an hour per IP | Auth | signup | POST | 3 per hour, per IP address |
| Uploads to a bucket | Storage | object/avatars/* | POST, PUT | 20 per hour, per user |
| An expensive function | Edge Functions | generate-report | Any | 5 per minute, per user |
| RPC functions by name | Database (REST API) | rpc/send_* | POST | 30 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
subof 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_rolekey 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-Aftergets through.
#What clients receive
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.
-- 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
| Limit | Free | Pro | Scale | Enterprise |
|---|---|---|---|---|
| Rate limit rules per project | 3 | 25 | 100 | 500 |
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.