curl -T / -F: Upload a File
There are two upload styles: PUT a file with -T, or multipart form with -F.
Uploading a build artifact or posting a form file are different transfers. Knowing which flag matches the API saves a lot of 400s.
What it does
-T / --upload-file <file> uploads the file using PUT by default, sending the raw bytes; you can change the method with -X. -F / --form sends a multipart/form-data POST, where each -F adds a field. For a file field, use -F 'field=@path' and optionally set the type with ;type=. Use -F when the API expects a form upload, -T when it expects a raw PUT body.
Common usage
curl -T build.tar.gz https://artifacts.example.com/uploads/build.tar.gz
curl -F 'file=@report.pdf' https://api.example.com/upload
curl -F 'file=@data.json;type=application/json' -F 'name=ci' https://api.example.com/upload
curl -X POST -T build.zip https://artifacts.example.com/x # PUT body via POSTFlags
| Flag | What it does |
|---|---|
| -T / --upload-file <f> | Upload the file (PUT by default), raw bytes |
| -F / --form 'k=@f' | Multipart form field reading a file |
| -F 'k=v' | Multipart form field with a literal value |
| -F 'k=@f;type=...' | Set the part content type |
| --form-string | Form field where @ and < are not special |
In CI
Match the flag to the API: a presigned S3-style PUT URL wants -T, while a typical upload endpoint wants -F. Pair uploads with -f so a rejected upload (413 too large, 401 unauthorized) fails the step rather than passing silently with an error body.
Common errors in CI
curl: (26) Failed to open/read local data from file/application means the @path in -F or the -T file is missing or unreadable. A 411 Length Required or 400 often means the API wanted multipart (-F) but got a raw PUT (-T), or vice versa.