Why File Uploads Are Hard
More than saving bytes
Accepting a JSON body is simple: parse it, validate the fields, store in the database. File uploads are different in every way: the data is binary (not text), the payload can be megabytes or gigabytes (not kilobytes), the encoding is different (multipart, not JSON), and the security risks are unique.
What can go wrong
Disk exhaustion. A user uploads a 10 GB file. Your server runs out of disk space. Other users cannot upload. The database cannot write. The app crashes.
Memory exhaustion. The server loads the entire file into memory before processing. A 500 MB file uses 500 MB of RAM. Ten concurrent uploads use 5 GB. The server runs out of memory and crashes.
Malicious files. A user uploads an executable renamed to .jpg. Another user downloads and runs it. Or the server processes the file (image resizing, PDF parsing) and a vulnerability in the processing library is exploited.
Path traversal. The user names their file ../../etc/passwd. If the server uses the filename directly to construct a file path, it writes to an unintended location.
MIME type spoofing. The user sets Content-Type: image/png but uploads a PHP script. If the server trusts the declared MIME type, it might serve the file with the wrong type, enabling XSS or code execution.
Denial of service. An attacker uploads thousands of tiny files (filling inodes), one massive file (filling disk), or a zip bomb (a small file that decompresses to terabytes).
What this course covers
Receiving files safely (Section 2): Parse multipart form data, validate file size and type before saving, sanitize filenames, reject dangerous uploads.
Serving files correctly (Section 3): Stream files from disk with correct headers, support range requests for video/audio, control access to private files.
Production patterns (Section 4): Stream uploads without loading into memory, process images (resize, thumbnail), track upload progress.
Cloud storage (Section 5): Upload directly to S3/R2 via presigned URLs (the file never touches your server), abstract the storage layer so you can swap implementations.
By the end, you will handle file uploads the way production apps do — safely, efficiently, and at scale.
Why is loading an entire uploaded file into memory dangerous?