Node.js › File Uploads & Media Processing

How would you implement direct-to-S3 file uploads from a client, avoiding routing large file uploads through your Node.js server entirely?

Advanced

Answer

Rather than having the client upload a file to your Node.js server, which then re-uploads it to S3 (doubling bandwidth usage and tying up server resources for the duration of potentially large uploads), you generate a pre-signed S3 URL server-side (a temporary, cryptographically-signed URL granting time-limited permission to upload directly to a specific S3 location) and return it to the client, which then uploads the file directly to S3 using that URL, with your server never touching the actual file bytes at all.
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
const { getSignedUrl } = require('@aws-sdk/s3-request-presigner');

app.post('/upload-url', async (req, res) => {
  const command = new PutObjectCommand({ Bucket: 'my-bucket', Key: `uploads/${crypto.randomUUID()}` });
  const url = await getSignedUrl(s3Client, command, { expiresIn: 300 });
  res.json({ uploadUrl: url });
});
Real-world example A video-sharing platform generates a pre-signed S3 URL for each upload request, letting users upload multi-gigabyte video files directly from their browser to S3, completely bypassing the Node.js server for the actual (potentially very slow) file transfer.

Common follow-ups: How does this pre-signed URL approach limit what the client is allowed to do (like restricting the file size or content type) despite the server never seeing the actual upload?;What's the tradeoff of this approach in terms of being able to validate or process the file before it's stored?