Rate limit policy
Understand and implement SuperTokens rate limit policies for managed and self-hosted services.
Overview
The following page describes how rate limits apply during SuperTokens API calls.
For managed service
The SuperTokens core of a managed account is rate limited on a per app and per IP address basis.
This means that if you query the core for app1 using the same IP address, the rate limit kicks in, and you get a 429 status code back from the core.
However, if you query the core using different IP addresses or for a different app, the rate limit of that does not interfere with the previous requests (that had another IP or was for another app).
Free tier
The free tier of the managed service has a rate limit of 50 requests per second with a burst of 50 requests per second (with no delay). This should be enough for 5-10 concurrent sign in / up (each sign in API call queries the SuperTokens core multiple times).
Paying users
If you are a paying user for SuperTokens, the rate limit and the burst limit adjust dynamically based on your usage (with a minimum of a 100rps).
You should not see any 429s unless there is a significant spike in requests.
Special case
The /hello API exposed by the core is commonly used for health checks.
This API does not require any API key, and has its own rate limit of 5 requests per second per app (regardless of the IP address querying it).
This is independent to the rate limit described above, and cannot change.
For self hosted
The SuperTokens core has no rate limit other than for the /hello API (which is 5 requests per second per app).
You can optionally cap concurrent requests per connection URI domain, as described in
Concurrency cap per connection URI domain.
You are free to add rate limits to the core by using a reverse proxy like Nginx.
If you want to implement rate limiting policy similar to the managed service described above, add the following to your http and server block in the nginx.conf file:
http {
# other configs..
map $request_uri $limit_req_zone_key {
"~^/(appId|appid)-(\w+)/?" $binary_remote_addr:$2;
default $binary_remote_addr;
}
limit_req_zone $limit_req_zone_key zone=mylimit:10m rate50/s;
limit_req_status 429;
# other configs..
upstream supertokens {
server localhost:3567;
}
server {
limit_req zone=mylimit burst=50 nodelay;
# other configs..
listen 0.0.0.0:80;
location / {
proxy_pass http://supertokens;
}
}
}
In the above, the core adds a rate limit per app per IP address.
Concurrency cap per connection URI domain
The concurrency cap requires Core 12.4.0 or later and is off by default.
A connection URI domain is the host name that backends use to reach the core. A self-hosted core usually has a single one, which all its apps share.
The cap limits how many requests from one connection URI domain the core processes at the same time, so that one domain
can’t take all the threads of the request pool (max_server_pool_size).
The core enforces it only while the pool is close to full:
- While more than
concurrency_cap_reserved_pool_percentof the pool’s threads are free, the core rejects no request. - Once fewer threads are free, a request that would take its connection URI domain above
max_concurrent_requests_per_cudrequests in flight gets an immediate429response with aRetry-After: 1header, instead of a thread.
For example, with max_server_pool_size: 10 and the default reserve of 25%, the core keeps 2 threads in reserve and
enforces the cap once more than 8 requests are in flight.
Only requests that pass the API key check for an app that exists under the connection URI domain count toward its cap.
Requests to routes without an API key check, such as /hello and /.well-known/jwks.json, and requests for an app that
doesn’t exist count toward the pool’s usage but are never capped.
Requests on the admin port don’t count at all.
| Configuration | Environment variable | Default | Description |
|---|---|---|---|
max_concurrent_requests_per_cud |
MAX_CONCURRENT_REQUESTS_PER_CUD |
0 |
Maximum concurrent requests per connection URI domain. 0 turns the cap off. Can’t exceed max_server_pool_size. |
concurrency_cap_reserved_pool_percent |
CONCURRENCY_CAP_RESERVED_POOL_PERCENT |
25 |
Share of max_server_pool_size, in percent, kept free before the cap applies. Must be between 1 and 100. 100 enforces the cap at all times. |
docker run \
-p 3567:3567 \
-e MAX_SERVER_POOL_SIZE=20 \
-e MAX_CONCURRENT_REQUESTS_PER_CUD=8 \
-d "$SUPERTOKENS_IMAGE"# You need to add the following to the config.yaml file.
# The file path can be found by running the "supertokens --help" command
max_server_pool_size: 20
max_concurrent_requests_per_cud: 8The backend SDK retries requests that get a 429 response.
The core’s /requests/stats API reports concurrentRequestsRejected, the number of an app’s requests that got a 429
from the cap, and concurrentRequestsInFlight, which covers the whole connection URI domain, so every app on the same
domain reports the same value.