The Problem
While building StreamSphere โ my full-stack video streaming platform โ I needed a way for users to upload videos directly to AWS S3. My first instinct was simple: user uploads to backend, backend receives the file, backend pushes it to S3. It sounded clean. It wasn't.
- Videos can be hundreds of megabytes or several gigabytes
- Every upload passed through the server twice โ once in, once out to S3
- This created unnecessary CPU, memory, and bandwidth load on the backend
Discovering Signed URLs
AWS provides something called a Pre-Signed URL. Instead of sending the file through the backend, the backend generates a temporary secure URL and hands it to the frontend. The frontend uploads the file directly to S3 using that URL. The actual file never touches the backend.
User โ Backend (get signed URL) โ AWS S3 (upload directly). The backend becomes a key dispenser, not a file highway.
Why This Approach Is Better
Once I understood signed URLs, the benefits were hard to ignore.
- Reduced server load โ the backend only generates a URL, not process gigabytes of video
- Faster uploads โ files go straight to S3 without a double-hop through the server
- Better scalability โ 10 users or 10,000, the backend workload stays flat
- Improved security โ no AWS credentials reach the frontend, and the URL expires in minutes
How I Implemented It
The implementation turned out to be surprisingly straightforward, broken into five clear steps.
- Step 1: User selects a video in the browser
- Step 2: Frontend requests a signed URL from the backend, sending file name, type, and upload folder
- Step 3: Backend uses the AWS SDK to generate a pre-signed URL with an expiry time, returning the upload URL, file key, and S3 object location
- Step 4: Frontend uploads the file directly to S3 using the signed URL โ backend is completely bypassed
- Step 5: On success, the app saves video title, description, S3 path, and upload date to the database
Challenges I Faced
Like most things in development, it didn't work perfectly on the first attempt. Three issues cost me the most time.
- CORS configuration โ the browser blocked upload requests because S3 wasn't set to accept requests from my frontend domain. Updating the bucket's CORS policy fixed it.
- Content-Type mismatches โ the file type sent during URL generation had to exactly match the type used during upload, or AWS rejected the request.
- Expiration time โ setting the expiry too short failed large uploads. I had to balance security against usability.
What I Learned
Before building this, I thought of file uploads as a minor feature. After shipping it, I understood it was an architectural decision disguised as a feature request.
Writing code is only part of software engineering. Understanding how data flows through a system โ and removing unnecessary bottlenecks โ can have a far bigger impact than adding more code.
Final Thoughts
If you're building anything that handles image uploads, video uploads, documents, or large files โ signed URLs are worth the extra hour it takes to understand them. They improve performance, reduce backend load, tighten security, and make applications easier to scale. For StreamSphere, switching to signed URL uploads transformed file handling from a server-heavy process into a lightweight, scalable solution. Sometimes the best optimization isn't writing faster code โ it's removing work that your system didn't need to do in the first place.