What they're testing
Whether you think about server bandwidth and memory, and whether you know the presigned-URL pattern.
The short answer~30 seconds
Don't route the file through your server. The client requests a presigned URL (the server checks permission, max size and content type, then signs it), uploads directly to S3/R2/Supabase Storage, then tells the server to record the metadata. Your server never holds the file in memory, spends no bandwidth, and scaling becomes the storage provider's problem rather than yours.
The long answer
The main reason isn't bandwidth but memory and connection-hold time. A 50MB upload on a slow connection occupies a thread or connection for minutes; a few dozen concurrent uploads is enough to stop an instance serving ordinary requests. Presigned URLs remove that entirely, in exchange for moving your checks to signing time, including a content-length-range constraint in the policy.
The security detail most often skipped is trusting the client-declared Content-Type. Anyone can set that header, so verify the actual content after upload — read magic bytes, and for images ideally reprocess through a library (resize, re-encode), which both normalises and strips payloads embedded in metadata. And always serve files from a domain separate from the app, so an HTML file that slips through can't execute in the user's session context.
Finally, orphans: the client gets a URL, uploads, then leaves before calling the confirm step. You have a file in storage with no database row. The remedy is uploading under a temporary prefix and moving it on confirmation, plus a lifecycle rule expiring that prefix after 24 hours — configured once on the bucket, with no cleanup job to write.
What they'll ask next
?What about very large files?
Multipart upload: split into parts, one presigned URL per part, uploaded in parallel with per-part retries. It also allows resuming after a connection drop rather than restarting from zero.
These lose points
- Reading the whole file into memory before writing it. With large files or concurrent uploads that's an OOM.
- Storing files on the container's disk. The container dies and they're gone, and with several instances each holds a different subset.