Uploading files is a feature you'll eventually need in almost every web application—whether it's profile pictures, PDFs, invoices, or media files. Instead of storing uploads on your server, Amazon S3 provides a reliable, scalable, and highly durable solution.
In this tutorial, we'll build a simple REST API using Node.js, Express, Multer, and AWS SDK v3 that uploads files directly to an Amazon S3 bucket.
Prerequisites
Before you begin, make sure you have:
- Node.js 18 or later
- An AWS account
- An Amazon S3 bucket
- An IAM user with programmatic access
- AWS Access Key ID and Secret Access Key
Step 1: Create a New Project
mkdir s3-upload-api
cd s3-upload-api
npm init -y
Install the required packages:
npm install express multer dotenv uuid @aws-sdk/client-s3
Step 2: Configure Environment Variables
Create a .env file.
AWS_REGION=ap-south-1
AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY
AWS_BUCKET_NAME=YOUR_BUCKET_NAME
PORT=3000
Create a .gitignore file.
node_modules
.env
Step 3: Configure the Amazon S3 Client
import { S3Client } from "@aws-sdk/client-s3";
const s3 = new S3Client({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
});
Step 4: Configure Multer
We'll use memory storage so files are uploaded directly to Amazon S3.
import multer from "multer";
const upload = multer({
storage: multer.memoryStorage(),
});
Step 5: Create the Upload Endpoint
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { v4 as uuid } from "uuid";
app.post("/upload", upload.single("file"), async (req, res) => {
try {
const filename = `${uuid()}-${req.file.originalname}`;
await s3.send(
new PutObjectCommand({
Bucket: process.env.AWS_BUCKET_NAME,
Key: filename,
Body: req.file.buffer,
ContentType: req.file.mimetype,
})
);
res.json({
success: true,
filename,
});
} catch (error) {
console.error(error);
res.status(500).json({
success: false,
message: "Upload failed",
});
}
});
Step 6: Start the Server
npm start
Step 7: Test with Postman
Send a POST request to:
POST http://localhost:3000/upload
Select:
Body → form-data
Key: file
Type: File
Choose any image or document and click Send.
Example response:
{
"success": true,
"filename": "4c6ddcf2-profile.png"
}
You should now see the uploaded file in your Amazon S3 bucket.
Common Errors
AccessDenied
Your IAM user doesn't have permission to upload objects. Make sure the user has the s3:PutObject permission.
NoSuchBucket
Verify the bucket name and AWS Region.
InvalidAccessKeyId
Check that your AWS credentials are correct.
Next Steps
Once the basic upload API is working, you can enhance it by:
- Supporting multiple file uploads
- Generating pre-signed URLs
- Validating file type and size
- Uploading directly from a React application
- Using CloudFront for faster content delivery
- Organizing uploads into folders
Further Reading
If you'd like to understand the concepts behind Amazon S3 before building production applications, these resources may help:
Conclusion
Building a file upload API with Node.js and Amazon S3 is straightforward once you understand the basic workflow. Using Express, Multer, and the AWS SDK v3, you can create a scalable upload service in just a few steps. From here, you can add authentication, pre-signed URLs, image processing, or integrate the API into your frontend application.
If you've implemented file uploads differently or have tips for improving this approach, feel free to share them in the comments.
Top comments (0)