Handling large file uploads without destroying the egress budget
Direct-to-object-storage patterns, multipart uploads, pre-signed URLs and the security points that keep large uploads from becoming an egress or security problem.
Routing large file uploads through the application server is the fastest way to turn a simple feature into an egress and bandwidth problem. The server receives the bytes, then sends them again to object storage, paying for the traffic twice and saturating its own network. The correct pattern is almost always client → object storage direct, with the application only handing out short-lived credentials or pre-signed URLs.
Direct-to-object-storage with pre-signed URLs
The application authenticates the user, decides the object key and any metadata, then returns a pre-signed PUT (or POST) URL that expires in minutes. The client uploads straight to the bucket. The application never sees the bulk of the bytes.
# Server-side generation (AWS example)
aws s3 presign s3://my-bucket/uploads/$(uuid).bin --expires-in 900
# Or use the SDK to generate a POST policy for browser uploads
Security points that still matter:
- Short expiry (5–15 minutes is usually enough)
- Content-Type and Content-Length conditions when possible
- Server-side encryption enforced by the bucket policy
- Virus / malware scanning after the object lands (async)
Multipart for reliability and size
Files larger than a few hundred MB should use multipart upload. The client initiates, uploads parts in parallel, and completes. Most SDKs and the browser File API support this. The application can still hand out the pre-signed URLs for each part or for the initiate/complete calls.
Avoiding the double-egress trap
If the application must process the file (transcode, virus scan, extract metadata), do it after the object is in storage, preferably with an event-driven worker in the same region. Pulling the object back to the application tier and then writing a derivative creates another egress or cross-AZ charge.
Measuring success
Origin or application egress should stay flat even when upload volume grows. The object-storage PUT volume should match the expected user upload volume. Any significant gap usually means the old proxy-through-app path is still in use somewhere.
Large uploads are a classic place where the architecture that is easiest to write on day one becomes the most expensive path later. Switching to direct-to-storage with short-lived pre-signed URLs removes the application from the data path and keeps the egress budget intact.

I also keep a simple test: upload a 1 GB file and watch the application’s network metrics. If the application’s egress rises by roughly 1 GB, the proxy path is still active. If only the object-storage metrics move, the direct path is working.
Related tools
Related reading
-
Object storage that doesn’t bleed money on downloads Practical trade-offs between public buckets, CDN, pre-signed URLs and lifecycle rules so downloads stop being the line item that quietly doubles your bill. -
Why your first cloud bill is always higher than the calculator The hidden line items that make the real invoice diverge from the pricing calculator: traffic, snapshots, public IPs, NAT, logging egress and the ways to find them with tags and Cost Explorer.