Introduction
Cloud Storage allows you to store files in a scalable way without managing physical servers. AWS S3 is the most widely used service for this purpose. This tutorial teaches you how to integrate S3 into a Node.js application, from setup to CRUD operations. You'll save time by avoiding common configuration mistakes.
Prerequisites
- Node.js 20+
- AWS account with access keys
- Basic TypeScript knowledge
- AWS CLI installed (optional)
Project Initialization
mkdir s3-cloud-storage
cd s3-cloud-storage
npm init -y
npm install @aws-sdk/client-s3 dotenv
npm install --save-dev typescript @types/node ts-node
npx tsc --initThis command creates a TypeScript project and installs the modern AWS S3 v3 SDK along with dotenv for environment variables.
AWS Configuration
import { S3Client } from '@aws-sdk/client-s3';
import * as dotenv from 'dotenv';
dotenv.config();
export const s3Client = new S3Client({
region: process.env.AWS_REGION || 'eu-west-3',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
});The S3 client is configured once. Always use environment variables for your keys to keep your code secure.
Upload a File
import { PutObjectCommand } from '@aws-sdk/client-s3';
import { s3Client } from './config';
import * as fs from 'fs';
async function uploadFile(bucket: string, key: string, filePath: string) {
const fileContent = fs.readFileSync(filePath);
const command = new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: fileContent,
ContentType: 'application/pdf',
});
await s3Client.send(command);
console.log(`Fichier uploadé : ${key}`);
}
uploadFile('mon-bucket-2026', 'documents/rapport.pdf', './rapport.pdf');PutObjectCommand allows you to upload any file. Always specify the ContentType for correct display in the AWS console.
Download a File
import { GetObjectCommand } from '@aws-sdk/client-s3';
import { s3Client } from './config';
import * as fs from 'fs';
async function downloadFile(bucket: string, key: string, outputPath: string) {
const command = new GetObjectCommand({ Bucket: bucket, Key: key });
const response = await s3Client.send(command);
const stream = response.Body as NodeJS.ReadableStream;
const writeStream = fs.createWriteStream(outputPath);
stream.pipe(writeStream);
console.log(`Fichier téléchargé : ${outputPath}`);
}
downloadFile('mon-bucket-2026', 'documents/rapport.pdf', './downloaded.pdf');GetObjectCommand returns a stream. Pipe it to a local file to save the content.
List Objects
import { ListObjectsV2Command } from '@aws-sdk/client-s3';
import { s3Client } from './config';
async function listFiles(bucket: string, prefix: string = '') {
const command = new ListObjectsV2Command({ Bucket: bucket, Prefix: prefix });
const response = await s3Client.send(command);
response.Contents?.forEach(obj => console.log(obj.Key));
}
listFiles('mon-bucket-2026', 'documents/');ListObjectsV2Command is the modern method for listing files. The prefix allows filtering by virtual folder.
Delete an Object
import { DeleteObjectCommand } from '@aws-sdk/client-s3';
import { s3Client } from './config';
async function deleteFile(bucket: string, key: string) {
const command = new DeleteObjectCommand({ Bucket: bucket, Key: key });
await s3Client.send(command);
console.log(`Fichier supprimé : ${key}`);
}
deleteFile('mon-bucket-2026', 'documents/rapport.pdf');DeleteObjectCommand permanently deletes an object. Note: there is no recycle bin by default on S3.
Best Practices
- Always use environment variables for credentials
- Enable versioning on your buckets in production
- Use consistent key names with prefixes
- Limit IAM permissions to the strict minimum
- Add tags to objects for cost tracking
Common Mistakes to Avoid
- Forgetting to configure the AWS region (signature error)
- Hardcoding credentials in the code
- Not handling network errors with try/catch
- Ignoring object size limits (5 GB for simple PutObject)
Going Further
Discover our complete cloud training to master AWS, GCP and Azure.