Your curl Has a Hidden Latency Profiler

One flag turns curl into a diagnostic tool that breaks down DNS, TCP, TLS, and transfer time.

Share

You fire off a request. It takes 800ms. Your service logs say the handler ran in 12ms. So where did the other 788ms go?

Most developers reach for browser DevTools or Wireshark at this point. But the answer is already in your terminal — you just need to ask curl the right question.

Why this matters

In production, "the API is slow" is rarely one thing. It could be DNS resolution, TCP handshake, TLS negotiation, a slow server response, or network transfer. Without knowing which phase is the bottleneck, you're guessing.

curl's --write-out flag prints timing data for every stage of the request lifecycle. No extra tools. No plugins. No browser tab.

How it works

Pass -w with format variables, and curl prints them to stdout after the transfer completes. The timing variables that matter:

  • time_namelookup — DNS resolution duration
  • time_connect — TCP handshake completion
  • time_appconnect — TLS handshake completion
  • time_starttransfer — time to first byte received (TTFB)
  • time_total — full request duration

Each value is in seconds, precise to the millisecond. The trick is subtraction. If time_namelookup is 400ms, DNS is your problem. If the gap between time_appconnect and time_starttransfer is 600ms, the server is slow. If time_total dwarfs time_starttransfer, it's payload size or bandwidth.

Where this helps

Debugging "the API is slow" — Compare TTFB against total time to instantly separate server-side processing from network overhead.

Investigating TLS cost — The gap between time_connect and time_appconnect shows exactly how long the handshake takes. Useful when evaluating mTLS or cert pinning overhead.

DNS troubleshooting — If time_namelookup spikes intermittently across requests, you have a resolver problem, not an application problem.

Comparing CDN regions — Run the same request against multiple regional endpoints and compare timing breakdowns side by side.

Watch out

The -w output goes to stdout and collides with the response body. Always pair it with -o /dev/null to discard the body. Use single quotes around the format string so your shell doesn't eat the % variables. And remember: curl only sees the client side. Server-internal breakdowns are lumped into TTFB with no further detail.

Try it yourself

curl -o /dev/null -s -w "DNS:     %{time_namelookup}s\nTCP:     %{time_connect}s\nTLS:     %{time_appconnect}s\nTTFB:    %{time_starttransfer}s\nTotal:   %{time_total}s\n" https://api.github.com/users/torvalds

TL;DR

  • What: curl's -w flag exposes per-phase timing for every request.
  • Why: It isolates DNS, TCP, TLS, TTFB, and transfer time with zero extra tooling.
  • Try: Run the snippet above against any endpoint that feels slow.