cURL by Example: Upload Raw Data
Send raw binary data from a file. Useful for APIs expecting binary bodies (e.g., images, protobufs).
Code
# Send binary file content as POST body
curl --data-binary @image.png -H "Content-Type: image/png" https://api.example.com/images
# Compare with -d (which strips newlines)
curl --data-binary @data.bin https://example.com/uploadExplanation
The --data-binary option is critical when uploading files that must maintain exact byte-for-byte integrity, particularly binary files like images, audio, video, executables, compressed archives, or any non-text data. The key difference between --data-binary and the regular -d flag is how they handle data: -d processes the data as text, stripping carriage returns (
), converting newlines, and removing trailing newlines, which is fine for URL-encoded form data but catastrophic for binary files where a single altered byte corrupts the entire file. --data-binary reads and sends data exactly as it exists on disk, preserving every byte including null bytes, line endings, and special characters—essential for maintaining file integrity.
When Binary Preservation Matters: Any file format that isn't plain ASCII text requires --data-binary. Image formats (JPEG, PNG, GIF, WebP) have specific header bytes and binary structures that break if even one byte changes. Compressed files (ZIP, GZIP, TAR) use binary compression algorithms where corruption causes extraction failure. Audio/video files (MP3, MP4, AVI) have precise timing and codec information encoded in binary. Executables and compiled code (EXE, DLL, SO, binary Python wheels) become non-functional if altered. Even text files with specific line ending requirements (CRLF vs LF) need binary mode to preserve their exact format. Protocol buffers, MessagePack, BSON, and other binary serialization formats require exact byte sequences. Using -d on any of these file types will corrupt them silently, often causing confusing errors when the server tries to process the damaged data.
Reading from Files vs Stdin: The --data-binary flag supports multiple source types. From file: --data-binary @filename.bin where the @ tells cURL to read content from the file. This is the most common usage: curl --data-binary @image.png -H "Content-Type: image/png" https://api.example.com/upload. From stdin: --data-binary @- reads from standard input, enabling powerful Unix-style pipelines: cat file.bin | curl --data-binary @- https://example.com/api or gzip -c largefile.txt | curl --data-binary @- https://api.example.com/upload to upload compressed data on the fly. Literal data: --data-binary $'binary dataÿ' for small inline binary sequences, though this is rarely practical for significant amounts of data.
Content-Type Headers and Binary Uploads: When uploading binary data, always explicitly set the appropriate Content-Type header to tell the server how to interpret the data. cURL doesn't automatically detect content types for --data-binary. Examples: -H "Content-Type: image/jpeg" for JPEG images, -H "Content-Type: application/octet-stream" for generic binary data, -H "Content-Type: application/zip" for ZIP archives, -H "Content-Type: application/pdf" for PDFs, -H "Content-Type: audio/mpeg" for MP3 files. The application/octet-stream content type serves as a universal fallback for "arbitrary binary data" when the specific type doesn't matter or is unknown. Note that --data-binary automatically uses POST method unless you override with -X PUT or another method, and it automatically sets Content-Length header based on the data size, which is required by most servers for binary uploads.
Code Breakdown
--data-binary @file reads file byte-for-byte.Content-Type header should match the binary data type.-d for anything other than text.
