Performance
API latency: where the milliseconds come from
Across twenty requests to /api/stats the median is 100 ms: 16 DNS, 19 TCP, 29 TLS and 36 server. A heavy endpoint pushes the server to 355 ms.
Key points
- API latency splits into DNS, TCP, TLS and server: curl prints each phase with -w.
- Across twenty requests to /api/stats the median is 100 ms, 36 ms of it server time.
- The handshake weighs 64 ms out of 100: on the first byte of the first request that is 64% of the time.
- On a 22 KB endpoint the server share rises to 355 ms: the query decides, not the network.
API latency is measured in four separate parts, not one number: DNS, TCP connection, TLS handshake and server time. Across twenty consecutive requests to https://ui.eneawork.it/api/stats the median is 100 ms, and only 36 ms of it belongs to the server: network and handshake spend the rest.
The breakdown of one request
| Phase | curl field | Median | Share |
|---|---|---|---|
| DNS | time_namelookup | 16 ms | 16% |
| TCP | time_connect - time_namelookup | 19 ms | 19% |
| TLS | time_appconnect - time_connect | 29 ms | 29% |
| Server and first byte | time_starttransfer - time_appconnect | 36 ms | 36% |
The four phases add up to 100 ms, which matches the median of time_total. Does the connection reuse the same socket across the series? No: every curl invocation opens a new connection, so the handshake is paid every time. That is the worst case, and it is the one a client sees when it calls the API once.
The command
for i in $(seq 1 20); do
curl -s -o /dev/null -w "%{time_namelookup} %{time_connect} %{time_appconnect} %{time_starttransfer} %{size_download}\n" \
https://example.com/api/stats
done
The command needs bash, curl and a connection. Replace the URL with your endpoint. time_appconnect stays zero on plain-text connections, so over HTTP the TLS phase disappears and the comparison with HTTPS stops being honest.
Where the time goes when the response grows
The light endpoint answers in 102 bytes; the tags one in 22,866 bytes, 224 times more, and it moves from 100 to 421 ms. The bytes do not explain the difference: at 1 Mbps, 22 KB travels in under 200 ms. The rest is server work, aggregating tags before it answers. The right question is not "how do I compress better", it is "why is this response built on every request".
The limitation to name
The numbers come from one network at one moment: latency to the server changes with the client position, and a CDN in front of the API moves the DNS and TLS phases to an edge. A burst of requests also returned 429: with a rate limiter in place, latency includes its decision, so measure at the same frequency the real client uses.
Where to continue
The EneUI catalogue indexes 111,985 components, 1,556 blocks and the brand speedtest icon, useful to give the latency panel a face. For the metric that contains this one, read TTFB: what it measures; to remove the first handshake, preconnect and dns-prefetch; for the weight of the bytes, Brotli against gzip; and for the comparison between architectures, frontend frameworks compared.
Frequently asked questions
What latency is acceptable for an API?
Under 200 ms at the 75th percentile an interface stays responsive. Above 500 ms the user notices the wait, and above 1 s behaviour changes. Read it next to the render time of the page that calls it.
Why does the first byte arrive after 36 ms when the response is 22 KB?
Because time_starttransfer measures the first byte, not the last. The remaining bytes show up in time_total. On large responses the gap between the two fields is the network part.
How much does the handshake cost on a single call?
In our measurement 64 ms out of 100, DNS, TCP and TLS together. On a page that makes ten calls to the same host, the cost is paid once if the connection stays open with keep-alive.
Does compression cut API latency?
It cuts byte transfer time, not server time. On a 22 KB JSON it helps; on a 100-byte response it adds work and can make the first byte worse.
How do I measure latency from my users' location?
With field data collected in the browser, not with curl from your laptop. A telemetry endpoint recording the client-side duration gives the real number; curl separates the phases when that number is high.