P50, P90, P95 and P99 latency, explained
A latency percentile is the response time that a given share of requests beat. P50 is the median: half of requests are faster. P95 means 95 of every 100 requests are faster, and the slowest 5 are not. P99 latency means 99 in 100 are faster, so only the slowest 1 in 100 are slower. Alert on P95: it catches a slowdown that real users feel without paging you for a single slow request.
Latency percentiles: what each one tells you
| Percentile | Meaning | Use it for |
|---|---|---|
| P50 (median) | Half of requests are faster | The typical experience; a slowdown that hits everyone |
| P90 | 9 in 10 requests are faster | An early sign that the slow tail is growing |
| P95 | 19 in 20 requests are faster | Alerting: users notice it, and it is stable enough not to flap |
| P99 | 99 in 100 requests are faster | The slow tail: timeouts, cold starts, lock waits, one bad dependency |
| Max | The single slowest request | Debugging only; one outlier moves it |
A worked example
Take 100 requests to one endpoint: 90 take 120 ms, 6 take 400 ms, 3 take 1,500 ms and 1 takes 4,000 ms. Sort them from fastest to slowest and read the value at each position.
| Measure | Value | How to read it |
|---|---|---|
| Average | 217 ms | Looks healthy, and matches no real request |
| P50 | 120 ms | The 50th request: most users are fine |
| P90 | 120 ms | The 90th request: still fine |
| P95 | 400 ms | The 95th request: 1 in 20 users waits over 3 times longer |
| P99 | 1,500 ms | The 99th request: 1 in 100 waits over a second |
| Max | 4,000 ms | One request, perhaps a cold start |
The average of 217 ms hides the problem: one user in ten waits at least 400 ms, and the slowest wait 1.5 to 4 seconds.
Why averages hide problems
An average mixes fast and slow requests into a number no user experienced. A handful of very slow requests among thousands barely moves it, and a burst of very fast ones, such as cache hits or health checks, can pull it down while real users wait. Percentiles describe the requests themselves, so a growing slow tail shows up as soon as it starts.
The tail also matters more than it looks. A page that makes 20 API calls hits at least one request slower than P99 about 18% of the time, because 1 − 0.9920 ≈ 0.18. For that page, nearly one visit in five waits on a P99-slow call.
Which percentile to alert on
- P95 for alerts. Set a threshold your users would call slow, and require it to hold for several minutes.
- P50 for regressions. If the median moves after a deploy, everyone got slower.
- P99 for investigation, not paging. On a quiet service it is noisy: with 50 requests in a 5-minute window, P99 is simply the slowest request.
- Latency with the error rate. A fast 500 is still a failure, so watch the share of 5xx errors next to P95.
Which percentiles each platform shows
| Platform | Percentiles shown | Latency alerts built in | Guide |
|---|---|---|---|
| Railway | P50, P90, P95, P99 per service | No; monitors cover CPU, RAM, disk and egress | Railway P95 latency alerts |
| Render | P50, P75, P90, P99 in the dashboard and P50, P95, P99 in the metrics stream, Pro workspace and up | No; notifications cover failures and disk | Render latency alerts |
| Vercel | P75 for functions with Observability Plus | No threshold alert; anomaly alerts on 5xx spikes | Vercel latency percentiles |
| Koyeb | P50, P90, P99 and max, as a 5-minute estimate | No | Koyeb latency alerts |
| Fly.io | A response-time histogram you query with PromQL | No | Fly.io latency percentiles |
| Heroku | Median, P95, P99 and max for web dynos | Yes, a P95 threshold on Professional and Fir dynos | |
| DigitalOcean App Platform | P95 request duration | Yes, P95 duration alert policies |