Edge Rate limiting
A slice accepts a set number of requests per minute, counted across every request that reaches it: its sites, /api/ and /trigger/ alike, however the request arrived. Past that number the router answers for the slice until the minute is over:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{"error":"rate limit exceeded"}How it counts
- One budget per slice, shared by every router replica, so a client spreading requests across them gets no more than one that does not.
- A fixed one-minute window. The count resets when the window does, so a burst that spans the boundary can spend most of two windows in quick succession. That is the trade for a counter that costs one increment per request.
- After the allowlist, before the site gate. A client the allowlist refuses spends nothing, and a visitor guessing at the site gate spends the budget like anyone else.
- A fronted host spends its target's budget. A hostname one slice fronts for another is counted against the slice that serves it.
- It fails open. If the shared counter cannot be reached, each router replica counts on its own rather than refusing traffic: the limit protects capacity, and failing closed would turn a cache outage into an outage.
It is a capacity control, not a security boundary, and a call made over a link does not pass the router at all.
Declaring it
edge {
rate_limit = "600/min"
}Write it per second, minute or hour ("10/s", "600/min", "3600/h"). The slice holds a whole number of requests per minute, so the CLI converts what you wrote and refuses a rate that does not convert to one, before anything is sent. Each refusal carries the position of the attribute in the file:
- Below one a minute:
Driftfile:13:16: Not a rate: edge.rate_limit: "30/h" is below one request per minute, the smallest rate a slice holds; the smallest you can write is "1/min" (or "60/h") - Not a whole number a minute:
Driftfile:13:16: Not a rate: edge.rate_limit: "90/h" is 1.5 requests per minute, and a slice holds a whole number per minute; write a multiple of 60/h, such as "60/h" or "120/h"
It is one limit with limits.requests_per_minute. The slice's limits block can write the same figure as a plain count, and a file that writes it in both places is refused: Driftfile:9:16: Written twice: edge.rate_limit and limits.requests_per_minute are one limit; write it in one place.
The rate is part of the slice's shape, so it reaches the slice with the resize drift apply makes, and drift plan shows it with the rest of the shape, as one line:
~ limits.requests_per_minute 60 → 600Left out of the file, the rate is the platform's own figure, the free slice's 60 a minute. A file that stops writing a rate it used to write is therefore a change like any other: the plan shows the figure falling back and lists it under Removes, which drift apply asks you to agree to.
The free slice's ceiling
A free slice is held to 60 requests per minute, the figure it is granted. A file with billing = "free" that declares more is refused before anything is sent: Driftfile:2:13: Not the free slice: billing is "free", and limits.requests_per_minute is 600, and the free slice grants 60. Make the shape smaller, or write billing = "monthly".
A configured slice has no ceiling here: requests per minute is not priced.
Limits
| Limit | Value |
|---|---|
| Smallest rate | 1 per minute (1/min or 60/h) |
| Per-hour rates | Multiples of 60 |
| Free slice | At most 60 per minute |
| Configured slice | No ceiling |
| Left out of the file | The platform's figure, 60 per minute |
| Window | One minute, fixed |
A 429 from a slice is this limit. A function out of memory to start another call answers 503 instead; Limits and alerts tells the two apart.