curl Cheatsheet
Forms and File Uploads
Use this curl reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
multipart with -F
-F / --form builds a multipart/form-data body, generates the boundary, and
switches the method to POST. Each -F is one part.
curl -F 'name=ada' -F 'role=admin' https://ex.com/profile curl -F 'avatar=@photo.png' https://ex.com/profile curl -F 'avatar=@photo.png' -F 'name=ada' https://ex.com/profile
| Form | Part sent |
|---|---|
-F 'k=v' | Text field k |
-F 'k=@path' | File upload, filename set from the path |
-F 'k=<path' | File contents as a text field, no filename |
-F 'k=@p;type=image/png' | Override the part's Content-Type |
-F 'k=@p;filename=x.png' | Override the advertised filename |
-F 'k=@p;headers="X-A: 1"' | Extra headers on that part |
-F 'k=@a,@b' | Two files in one multipart/mixed part |
--form-string 'k=v' | Literal value, @ and < not special |
curl -F 'file=@report.csv;type=text/csv;filename=q3.csv' \ https://ex.com/import curl --form-string 'body=@mention is literal here' https://ex.com/post
Never mix -F with -d. They build mutually exclusive bodies and curl errors
out rather than merging them.
Reading from stdin
A dash as the path reads stdin, which is how you upload something generated on the fly. curl cannot know the length up front, so it uses chunked transfer encoding.
tar czf - ./src | curl -F 'archive=@-;filename=src.tgz' https://ex.com/up
pg_dump db | gzip | curl -T - https://ex.com/backups/db.sql.gzSome servers and older proxies reject chunked uploads. If you get a 411, write to
a temp file first so curl can send a real Content-Length.
PUT with -T
-T / --upload-file sends the file as the whole body with PUT, no multipart
wrapper. This is what object stores and WebDAV endpoints expect.
curl -T backup.tar.gz https://ex.com/files/backup.tar.gz curl -T backup.tar.gz https://ex.com/files/ # trailing / keeps the name curl -T '{a.txt,b.txt}' https://ex.com/files/ # two PUTs, one process
A trailing slash on the URL means curl appends the local basename. Without it,
the URL path is used verbatim, so -T a.txt https://ex.com/files overwrites
/files.
Field names with special characters
The -F parser treats =, @, <, ;, and , as syntax, so escape them with
a backslash on the command line. Separately, curl percent-encodes field names and
filenames that contain special characters when it writes the part headers.
--form-escape (curl 7.81.0) switches that to backslash-escaping instead, for
servers whose multipart parser does not decode percent-escapes.
curl -F 'a\,b=1' https://ex.com/f # literal comma in the name curl -F 'file=@"tax 2025".pdf' https://ex.com/f # quoted path with a space curl --form-escape -F 'field\name=curl' https://ex.com/f curl --form-string 'query=a=b&c=d' https://ex.com/f
--form-string is the safe choice whenever the value is user data, because it
turns off every special meaning.
Resuming and large files
| Flag | Purpose |
|---|---|
-C - / --continue-at - | Resume, let curl find the offset |
-C <n> | Resume at byte n |
--limit-rate 2M | Cap throughput |
--max-time <s> | Wall clock cap on the transfer |
--expect100-timeout <s> | How long to wait for 100 Continue |
-H 'Expect:' | Disable the 100-continue handshake |
--max-filesize <n> | Refuse a download larger than n |
curl -C - -T big.iso https://ex.com/up/big.iso
curl -C - -O https://ex.com/big.iso # resume a download
curl --limit-rate 2M -T big.iso https://ex.com/up/curl adds Expect: 100-continue for bodies over 1 MB. If a server never answers
it, curl stalls for one second and then sends anyway, so -H 'Expect:' removes
the pause.
Verifying what was sent
Multipart bugs are almost always a wrong boundary, filename, or part Content-Type. Dump the real body rather than guessing.
curl -v -F 'f=@a.png' https://ex.com/up 2>&1 | grep -i 'content-' curl --trace-ascii - -F 'f=@a.png' https://ex.com/up | head -40 curl -F 'f=@a.png' https://httpbin.org/post # echoes the parsed parts
--trace-ascii - prints the full outgoing body including the boundary lines,
which -v alone hides.