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.

Recipe:
Response & inspection
Headers & identity

Custom headers

Authentication
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 HEAD request 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 OPTIONS request carrying Origin, Access-Control-Request-Method and Access-Control-Request-Headers. Read the response's Access-Control-Allow-* headers to see what the server permits.
Test caching — conditional request
Send the ETag you got back as If-None-Match (or a date as If-Modified-Since). A 304 Not Modified confirms caching/revalidation works. Inspect Cache-Control, Expires, Age and CDN headers like X-Cache / CF-Cache-Status in the headers-only view.
POST JSON — -d + Content-Type
The #1 mistake is forgetting Content-Type: application/json, so this recipe adds it automatically. -d already implies POST, so no separate -X POST is 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