curl Cheatsheet

Basics

Use this curl reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Shape of a curl command

curl [options] [URL...]. Options may come before or after the URL, and the default method is GET with the body written to stdout.

curl https://api.example.com/users        # GET, body to stdout
curl -s https://api.example.com/users     # no progress meter
curl -sS https://api.example.com/users    # quiet, but still show errors
curl -i https://api.example.com/users     # headers + body
curl -I https://api.example.com/users     # headers only (HEAD)

Multiple URLs in one invocation reuse the connection. --next (or -:) starts a fresh option set for the URL that follows it, which is how you send two different requests in one process.

curl -s https://a.example.com/ -: -X POST -d x=1 https://b.example.com/

The flag table

Short and long form together, because both get searched. This is the set that covers almost every real invocation.

FlagLong formDoes
-X--request <m>Set the method (GET, POST, PUT, DELETE, ...)
-H--header <h>Add a request header, repeatable
-d--data <s>POST body, @file reads a file, newlines stripped
—--data-raw <s>Same, but a leading @ is literal
—--data-binary <s>Send bytes exactly, no newline stripping
—--data-urlencode <s>Percent-encode before sending
—--json <s>Body plus Content-Type and Accept: application/json
-F--form <n=v>multipart/form-data field, @file uploads
-G--getMove -d data into the query string, use GET
-T--upload-file <f>PUT a file
-u--user <u:p>Basic auth credentials
—--oauth2-bearer <t>Authorization: Bearer <t>
-b--cookie <s|f>Send cookies from a string or a file
-c--cookie-jar <f>Write received cookies to a file
-e--referer <url>Set Referer
-A--user-agent <s>Set User-Agent
-L--locationFollow redirects
—--max-redirs <n>Cap redirect hops, -1 for unlimited
—--retry <n>Retry transient failures
—--retry-all-errorsRetry on any error, not just transient ones
-k--insecureSkip TLS verification
—--cacert <f>Verify against this CA bundle
-E--cert <f[:pw]>Client certificate
—--key <f>Client private key
—--tlsv1.2Minimum TLS version
—--resolve <h:p:ip>Fake DNS for one host and port
-x--proxy <url>Route through a proxy
-o--output <f>Write body to a file
-O--remote-nameWrite body to the URL's basename
-s--silentNo progress meter, no error text
-S--show-errorRe-enable error text under -s
-f--failExit 22 on HTTP ≥ 400, discard the body
-i--includePrepend response headers to the output
-I--headHEAD request, headers only
-v--verboseProtocol trace on stderr
—--trace-ascii <f>Full readable trace including bodies
-w--write-out <fmt>Print a template after the transfer
—--connect-timeout <s>Cap the connect phase
—--max-time <s>Cap the whole transfer
—--compressedRequest and transparently decode gzip/br
—--http2Negotiate HTTP/2
—--http3Use HTTP/3 over QUIC
—--unix-socket <p>Talk to a Unix domain socket

URL globbing

curl expands {} and [] in URLs unless you pass -g / --globoff. Handy for batches, surprising when a URL legitimately contains a brace.

curl -O "https://ex.com/img[001-010].png"    # 10 downloads
curl "https://ex.com/{users,orgs,repos}"     # 3 requests
curl -g "https://ex.com/search?q=a[0]"       # globbing off, literal

#1 and #2 in an -o template refer to the first and second glob, which is how you name the outputs.

curl "https://ex.com/{a,b}/img[1-3].png" -o "#1-#2.png"

.curlrc

A per-user default option file. One option per line, long form, no leading dashes needed, # comments. Search order is $CURL_HOME/.curlrc, then $XDG_CONFIG_HOME/curlrc, then $HOME/.curlrc.

# ~/.curlrc
silent
show-error
location
compressed
connect-timeout = 10
max-time = 60
user-agent = "curl-local"

Load a different file with -K file / --config file, and skip .curlrc entirely with -q as the first argument.

A .curlrc that sets insecure or silent is a classic debugging trap, because every later curl on that machine behaves differently from the command you pasted into a ticket. Reproduce with curl -q when a result looks wrong.

Exit codes

curl exits 0 on a completed transfer even when the server answered 404. Use -f if a bad status should fail the script.

CodeMeaning
0Success
3Malformed URL
6Could not resolve host
7Failed to connect
22HTTP error ≥ 400, requires -f
28Timeout (--connect-timeout or --max-time)
35TLS handshake failure
47Too many redirects
52Empty reply from server
60Peer certificate could not be verified
curl -fsS https://api.example.com/health || echo "health check failed: $?"

--fail-with-body is the variant that still prints the error body, which is usually what you want against a JSON API that explains itself in the 4xx.