curl Cheat Sheet

Most used
curl -LO https://example.com/file.tar.gz          # download, keep remote name
curl -I https://example.com                       # response headers only
curl -sS https://api.example.com/v1/items | jq    # quiet, but still show errors
curl --json '{"name":"x"}' https://api.example.com/v1/items   # POST JSON
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/v1/me
curl -v https://example.com -o /dev/null          # debug the connection and TLS

Syntax: curl [options] URL.... By default curl does a GET and writes the body to standard output, with a progress meter on standard error when output is redirected. It is preinstalled on Ubuntu, Fedora and most other distros; otherwise install the curl package with apt, dnf, pacman or zypper. Check your version with curl --version, since a few options below need a recent release.

Downloading

CommandWhat it does
curl -O URLSave under the remote file name
curl -o name.ext URLSave under a name you choose
curl -L URLFollow redirects (301, 302, 307, 308)
curl -LOJ URLUse the file name from the server's Content-Disposition header
curl -C - -LO URLResume an interrupted download
curl --limit-rate 2M -LO URLLimit speed to 2 MB/s
curl -LO URL1 -LO URL2Several downloads in one command (-Z for parallel)
curl -LO 'https://host/img[01-20].jpg'URL globbing: ranges and {a,b,c} lists
curl -f -LO URLFail (exit 22) on HTTP 4xx/5xx instead of saving the error page
curl -# -LO URLSimple progress bar
curl --create-dirs -o dl/a/b.txt URLCreate missing directories for the output file

Requests, headers and data

CommandWhat it does
curl -X DELETE URLUse another HTTP method (PUT, PATCH, DELETE)
curl -H 'Accept: application/json' URLAdd or override a request header
curl -A 'Mozilla/5.0' URLSet the User-Agent
curl -e https://ref.example URLSet the Referer
curl -d 'a=1&b=2' URLPOST URL-encoded form data
curl --data-urlencode 'q=hello world' URLPOST with the value URL-encoded for you
curl -G --data-urlencode 'q=linux' URLPut the data in the query string of a GET instead
curl --json @body.json URLPOST JSON from a file, sets Content-Type and Accept (curl 7.82+)
curl -H 'Content-Type: application/json' -d '{"a":1}' URLPOST JSON on older curl versions
curl -F '[email protected]' -F 'title=Hi' URLmultipart/form-data upload, like an HTML form
curl -T file.txt URLUpload a file with PUT (also works for FTP/SFTP)
curl --variable %TOKEN --expand-header 'Authorization: Bearer {{TOKEN}}' URLInsert an environment variable into an option without exposing it in ps (curl 8.3+)

Authentication and cookies

CommandWhat it does
curl -u alice URLHTTP Basic auth, prompt for the password
curl -u alice:secret URLPassword on the command line (visible in history and ps)
curl -n URLRead credentials from ~/.netrc
curl -H "Authorization: Bearer $TOKEN" URLBearer token (OAuth, most REST APIs)
curl --oauth2-bearer "$TOKEN" URLSame, built-in option
curl -b 'session=abc' URLSend a cookie
curl -c jar.txt -b jar.txt URLSave and reuse cookies across requests
curl --cert client.pem --key client.key URLTLS client certificate (mutual TLS)

Output, debugging and timing

CommandWhat it does
curl -I URLHEAD request: headers only
curl -i URLInclude response headers before the body
curl -v URLVerbose: DNS, connection, TLS handshake, request and response headers
curl --trace-ascii - URLFull dump of everything sent and received
curl -s URLSilent: no progress meter or errors
curl -sS URLSilent but still print errors (best for scripts)
curl -o /dev/null -s -w '%{http_code}\n' URLPrint only the status code
curl -o /dev/null -s -w '%{time_namelookup} %{time_connect} %{time_starttransfer} %{time_total}\n' URLWhere the time goes: DNS, TCP, first byte, total
curl -D headers.txt -o body.html URLSave headers and body to separate files
curl -w '%{json}' -o /dev/null -s URL | jqAll transfer variables as JSON

Connections, TLS, proxies and retries

CommandWhat it does
curl --connect-timeout 5 -m 30 URL5 s to connect, 30 s for the whole transfer
curl --retry 5 --retry-delay 2 --retry-all-errors URLRetry transient failures
curl -4 URL / curl -6 URLForce IPv4 or IPv6
curl --resolve example.com:443:203.0.113.10 https://example.comSend to a specific IP without editing /etc/hosts (test a new server)
curl --connect-to example.com:443:new.example.net:443 https://example.comSame idea, by host name
curl -x http://proxy:3128 URLUse an HTTP proxy (also honours https_proxy env vars)
curl --socks5-hostname localhost:1080 URLUse a SOCKS5 proxy, for example ssh -D 1080
curl --cacert ca.pem URLTrust a private CA for this request
curl --http2 / --http3Request a protocol version (HTTP/3 needs a build with it)
curl --compressed URLAsk for gzip/brotli/zstd and decompress automatically
curl -k URLSkip certificate verification. Testing only.

Common recipes

Check a list of URLs and print status code and total time:

while read -r u; do
  curl -o /dev/null -sS -w "%{http_code} %{time_total}s $u\n" --max-time 10 "$u"
done < urls.txt

Show a site's certificate dates and issuer (the SSL expiry check script automates this):

curl -vsI https://example.com 2>&1 | grep -E 'expire date|start date|issuer|subject:'

Call a JSON API, fail on HTTP errors and extract a field:

curl -fsS -H "Authorization: Bearer $TOKEN" https://api.example.com/v1/user | jq -r '.login'

Test a new server before switching DNS:

curl -sI --resolve www.example.com:443:203.0.113.10 https://www.example.com | head -5

Find your public IP address:

curl -s https://ifconfig.me; echo

Query a local API on a Unix socket (Docker):

curl -s --unix-socket /var/run/docker.sock http://localhost/version | jq .Version

Download and verify before running an installer, instead of piping to a shell:

curl -fsSLo install.sh https://example.com/install.sh
less install.sh          # read it
sha256sum install.sh     # compare with the published checksum
bash install.sh

Gotchas

  • No redirects by default. Without -L you save a tiny HTML redirect page instead of the file.
  • HTTP errors exit 0. A 404 or 500 is a successful transfer to curl. Use -f (or --fail-with-body) in scripts.
  • -d switches to POST. Adding -X POST as well is redundant, and -X GET -d ... sends a body with GET, which many servers ignore. Use -G for query strings.
  • Shell quoting. Use single quotes around JSON so the shell leaves $ and " alone; use double quotes only when you need a variable expanded, or put the body in a file with -d @file.
  • curl | sudo bash runs code you have not read as root. Download, inspect, and prefer a distro package or an official repository.
  • Name resolution failures. curl: (6) Could not resolve host is a DNS problem on your side; see Temporary failure in name resolution.
  • Secrets on the command line are visible to other users in ps. Use -u user without the password, ~/.netrc, or -H @headers.txt.

The full manual is at curl.se/docs/manpage.html and Everything curl.

Frequently asked questions

How do I download a file with curl?

Use curl -LO URL to save it under its remote name, or curl -L -o name.iso URL to choose the name. -L follows redirects, which most download links use.

How do I send JSON with curl?

On curl 7.82 or newer use curl --json '{"key":"value"}' URL. On older versions use -H 'Content-Type: application/json' -d '{...}'. Read the body from a file with -d @body.json.

How do I see the response headers?

curl -I URL sends a HEAD request and prints only the headers. curl -i URL prints headers and body, and curl -v URL also shows the request and TLS handshake.

Is curl -k safe?

Only for a quick test against your own server. -k disables certificate checks, so anyone in the middle can read and change the traffic. Fix the certificate or point curl at the right CA with --cacert.

What is the difference between curl and wget?

curl writes to standard output and supports many protocols and request types, so it suits APIs and scripts. wget saves to a file by default and can mirror websites recursively, so it suits bulk downloads.

Spotted a mistake or a command that no longer works? Send a correction — pages are re-checked when reports come in.