The Complete curl Command Guide: Every Flag You'll Actually Use
2026-08-17
curl https://example.com is the most-installed HTTP client on the planet, and it’s hiding in plain sight: the single most useful debugging tool a developer owns, outshone only by the documentation gap around it. Once you learn a dozen flags, curl becomes the fastest way to probe an API, reproduce a bug, and test a fix without opening a browser or writing a throwaway script. This guide walks through the flags in the order you’ll actually need them.
The Anatomy of a curl Command
A curl invocation is one URL plus zero or more flags:
curl [flags] URL
By default curl sends a GET request and writes the response body to standard output. The flags are what turn that bare command into a full HTTP client — and since flags are order-independent, the same command can be written several ways. If you ever get a flag’s behavior wrong, curl --help lists everything and curl --help all shows the full manual.
Reading Responses: -i, -I, -L, -s
The body alone rarely tells you enough. Three flags make the response legible:
curl -i https://api.example.com/users # include response headers
curl -I https://api.example.com/users # HEAD only: headers, no body
curl -L https://example.com/login # follow redirects (3xx)
-i/--include— prints the response status line and headers above the body. The first thing to add when a request “doesn’t work,” because the status code is where the answer starts.-I/--head— sends a HEAD request (see the HTTP methods guide for what that means) and prints headers only. Great for checking existence, size, or content-type of a resource without downloading it.-L/--location— re-issues the request at every redirect location. Without it, a 301/302 just prints the redirect response and stops — a classic “why is my curl returning HTML for an API call?” gotcha.-s/--silent— suppresses the progress meter. Pair it with-S(--show-error) so errors still print:-sSis the quiet-but-informative combo for scripts.
Headers and Methods: -H, -X
Custom headers and explicit methods are where curl starts feeling like a real client:
curl -X POST https://api.example.com/users
curl -H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
https://api.example.com/users/7
-H "Name: value"— sets one request header. Repeat the flag for multiple headers; use-Hwith an empty value to unset a default.-X METHOD— sets the HTTP method. Common gotcha: curl’s-X POSToverrides only the method, not the implicit behaviors that-dor-Ftrigger (like settingContent-Type). In practice you rarely need-X— sending-dalready implies POST, and-Fimplies multipart POST — but-X PUT,-X PATCH, and-X DELETEare what you’ll reach for.
Sending Data: -d, JSON, —data-binary
curl -d "name=ada&role=admin" https://api.example.com/users # form-encoded
curl -H "Content-Type: application/json" \
-d '{"name": "ada", "role": "admin"}' \
https://api.example.com/users # JSON
curl --data-binary @body.json https://api.example.com/users # raw file body
-d "key=value"/--data— sends form-encoded data (application/x-www-form-urlencoded) and implies POST. Multiple-dflags are concatenated with&automatically.- With
-H "Content-Type: application/json"and a JSON string, the same-dsends a JSON body — this is the workhorse of every API call you’ll ever make. --data-binary @file— sends the file’s contents verbatim as the request body (no newline stripping). Prefix with@any time the body comes from a file.- To log the exact request curl is building, add
-v(below) — the body and headers will be visible.
Files: -o, -O, -F, -T
curl -o report.pdf https://example.com/report.pdf # save body to a named file
curl -O https://example.com/report.pdf # save with remote filename
curl -F "avatar=@photo.png" https://example.com/upload # multipart file upload
curl -F "avatar=@photo.png;type=image/png" https://example.com/upload
curl -T backup.zip https://example.com/uploads/ # PUT a file
-o file/-O— write the body to a file instead of stdout. Use-o /dev/nullto discard a large body while keeping the headers visible.-F "field=@file"— multipart/form-data upload, the equivalent of an HTML<input type="file">form. Add;type=to force the Content-Type of the uploaded part.-T file/--upload-file— PUT the file’s contents to the URL. Combine with a download flag for a quick backup round-trip.
Cookies, Auth, and Sessions
curl -b "session=abc123" https://example.com/me # send a cookie manually
curl -c cookies.txt https://example.com/login # save cookies to a jar
curl -b cookies.txt https://example.com/me # replay them later
curl -u user:pass https://api.example.com/private # HTTP Basic auth
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/private
-b— sends cookies, either as an inline"name=value"string or from a file (cookie jar / Netscape format).-cwrites the cookies a response sets into a jar.- The classic session dance:
-cto capture the login cookie, then-bto replay it on subsequent requests — the terminal equivalent of a logged-in browser tab. -u user:pass— HTTP Basic auth (base64-encoded in the header). For token APIs, theAuthorization: Bearerheader is more common.
Debugging: -v, -w, -f
curl -v https://api.example.com/users # verbose: full request/response
curl -w "\n%{http_code} in %{time_total}s\n" https://api.example.com/users
curl -f https://api.example.com/users/404 # exit non-zero on HTTP errors
-v/--verbose— prints the entire request line, request headers, TLS handshake details, and response headers. When nothing else makes sense,-vshows you exactly what went over the wire.--trace-ascii -shows even the raw bytes.-w 'format'/--write-out— prints extra info after the response.%{http_code},%{time_total}, and%{size_download}are the ones you’ll use to measure API latency or confirm a status without parsing the body.%{redirect_url}shows where a 3xx wanted to go.-f/--fail— makes curl exit with a non-zero code (22) on HTTP 4xx/5xx instead of printing the error page and “succeeding.” Essential for scripts that need to know a request actually failed.
Timeouts and Retries
curl --connect-timeout 5 https://api.example.com # fail if TCP connect stalls
curl -m 30 https://api.example.com/slow # hard total-time cap
curl --retry 3 --retry-delay 2 https://api.example.com/jittery
--connect-timeoutbounds only the connection phase — use it to fail fast on unreachable hosts.-m/--max-timebounds the whole operation — the guardrail for endpoints that hang.--retry Nretries on transient failures (with a delay between attempts); combined with a non-idempotent method, be aware you may be replaying a POST — the HTTP methods guide explains why that matters.
Practical Tips
- Start minimal, add as needed:
curl -ifirst, then add-Lfor redirects, then-Hand-donce you know the shape of the request. - Never paste secrets into shared chats — put tokens in an environment variable (
$TOKEN) and reference it, as in the examples above. - Turn curl into code: once you’ve confirmed a request works, the curl Converter tool turns the exact command into JavaScript
fetch, Python, Go, and other languages — no need to hand-translate. - Look up the status code you just got with the HTTP Status Reference — knowing that 405 means “wrong method” (and that the
Allowheader lists the right ones) resolves most API mysteries. - Save your most-used incantations as shell aliases or a small script; a
cget()/cjson()wrapper covers 90% of daily API work.
Quick Reference
curl -i URL— see status + headers.curl -L URL— follow redirects.curl -sS URL— quiet but show errors.-H "Name: value"for headers; repeat for more.-X PUT/-X PATCH/-X DELETEto change the method.-d "k=v"= form POST;-d '{"json":...}'+-H "Content-Type: application/json"= JSON POST;--data-binary @file= raw body.-o filesave,-Osave by remote name,-F "field=@file"multipart upload,-T filePUT upload.-bsend cookies,-csave cookies,-u user:passBasic auth,Bearervia-H "Authorization: ...".-vverbose wire dump,-w '%{http_code}'print status,-ffail on HTTP errors.--connect-timeout,-m(max time),--retry Nkeep flaky requests from hanging forever.