Command builder
curl command builder
For the things you only do occasionally — inspect a response, download a file, or call an API. Build a command from options, or Explain one you've been handed. Quoting is correct for your shell.
Save to disk
Most download links redirect — keep Follow redirects on above. -O needs a filename in the URL; if the URL has none, pick “Choose a filename” instead.
Upload a file
-T sends the file's raw bytes as a PUT (no -X needed). If the URL ends in /, curl appends the filename — e.g. -T report.pdf https://host/uploads/ uploads to …/uploads/report.pdf. This is different from -F (multipart form upload) over in Call an API.
Response & inspection
Headers & identity
Custom headers
Authentication
Request body
Form fields (value @path uploads a file)
CORS preflight
Caching / conditional
TLS & connection
Resolve host to a specific IP --resolve (test a CDN edge / staging server)
Build or explain
Two tabs at the top. Build a command assembles one from options. Explain a command goes the other way — paste a curl command someone handed you (from a README, a Stack Overflow answer, your browser's “Copy as cURL”) and it breaks down the method, the URL and every flag in plain language. It covers the ~50 most common flags; anything it doesn't recognise is marked rather than guessed at, and it assumes bash/zsh quoting.
The four modes
curl really does a few different jobs, and they barely overlap — so the tool leads with them. The difference is what flows where: Inspect prints the response to your terminal (headers, redirects, timing); Download writes the response to a file on disk; Upload sends a local file up to the server; Call an API is about sending structured data (JSON, forms, auth) and reading the reply. They conflict on purpose — you can't both print headers only and save the body to a file — which is why picking a mode swaps the relevant options in and out. Headers, auth and TLS settings stay available in every mode.
Downloading: -o vs -O
The classic trap. -O (capital O) saves the file using the name from the URL — curl -O https://x.com/report.pdf writes report.pdf. -o name (lowercase o) saves to a filename you choose — curl -o my.pdf https://x.com/report.pdf. Mnemonic: lowercase -o = the output name is yours; capital -O = use the Original name. Companions: -J honours a filename the server suggests (via Content-Disposition, pairs with -O); -C - resumes a half-finished download; --output-dir picks the folder; and almost every download link redirects, so keep -L on. Note -O fails if the URL ends in a slash with no filename — choose a name instead.
Uploading: -T
-T file is the mirror image of -O: it sends a local file to the URL as the raw request body, which curl turns into a PUT (so no -X is needed). If the URL ends in /, curl appends the local filename — curl -T report.pdf https://host/uploads/ PUTs to …/uploads/report.pdf. Don't confuse it with -F field=@file (a multipart form upload, like an HTML form) or -d @file (posts the file's text as the body) — -T is the plain "PUT this file" upload used by REST APIs, S3-style stores and WebDAV.
The recipes, explained
- Headers only —
-I - Sends a
HEADrequest and prints just the response headers. The classic confusion:-I= headers only;-i= headers plus body. Don't use-X HEAD— it can hang waiting for a body that never comes. - Trace redirects —
-sIL - Follows the redirect chain (
-L) and prints each hop's headers (-I), quietly (-s). The fastest way to see where a URL really ends up and with which status codes. Note: by default curl does not follow redirects. - Test CORS — preflight
OPTIONS - Browsers send a preflight before certain cross-origin requests. This reproduces it: an
OPTIONSrequest carryingOrigin,Access-Control-Request-MethodandAccess-Control-Request-Headers. Read the response'sAccess-Control-Allow-*headers to see what the server permits. - Test caching — conditional request
- Send the
ETagyou got back asIf-None-Match(or a date asIf-Modified-Since). A304 Not Modifiedconfirms caching/revalidation works. InspectCache-Control,Expires,Ageand CDN headers likeX-Cache/CF-Cache-Statusin the headers-only view. - POST JSON —
-d+Content-Type - The #1 mistake is forgetting
Content-Type: application/json, so this recipe adds it automatically.-dalready impliesPOST, so no separate-X POSTis emitted. - Timing breakdown —
-w - Prints DNS, connect, TLS, time-to-first-byte and total times — for answering "why is this slow?" without a profiler.
Why the shell toggle?
bash/zsh wrap strings in single quotes, so JSON like {"a":1} pastes cleanly. Windows shells don't: CMD has no single-quote string, so quotes must be doubled and inner ones escaped; PowerShell aliases curl to a different command, so the binary is written as curl.exe, and the null device is NUL not /dev/null. Pick your shell and the command is rewritten to paste correctly.
Two security notes
-k (skip TLS verification) defeats the point of HTTPS — use it only against known staging/self-signed hosts, never in scripts that touch real data. On a redirect to a different host, curl drops the Authorization header on purpose so your token can't leak to another origin.
Sources & references
- everything.curl.dev — the curl bookcurl project
- curl man pagecurl.se
- Cross-Origin Resource Sharing (CORS)MDN
- HTTP cachingMDN