AWS SDK for JavaScript (v3)
The AWS SDK for JavaScript v3 is the modern, modular SDK from AWS — small bundle sizes, tree-shakeable, and runs in Node.js, the browser, React Native, Bun, and Deno.
Install
npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner
| Package | What it's for |
|---|---|
@aws-sdk/client-s3 | The core S3 client and command classes |
@aws-sdk/lib-storage | High-level uploader (handles multipart automatically) |
@aws-sdk/s3-request-presigner | Pre-signed URL generation |
Initialize the client
import { S3Client } from '@aws-sdk/client-s3';
export const s3 = new S3Client({
endpoint: 'https://s3.filebase.io',
region: 'auto',
credentials: {
accessKeyId: process.env.FILEBASE_KEY!,
secretAccessKey: process.env.FILEBASE_SECRET!,
},
});
List buckets
import { ListBucketsCommand } from '@aws-sdk/client-s3';
const result = await s3.send(new ListBucketsCommand({}));
for (const b of result.Buckets ?? []) {
console.log(b.Name);
}
Create a bucket
import { CreateBucketCommand } from '@aws-sdk/client-s3';
await s3.send(new CreateBucketCommand({ Bucket: 'my-bucket' }));
For a public bucket, add ACL: 'public-read':
await s3.send(
new CreateBucketCommand({ Bucket: 'my-public-bucket', ACL: 'public-read' }),
);
Upload an object
import { PutObjectCommand } from '@aws-sdk/client-s3';
import { readFile } from 'node:fs/promises';
const body = await readFile('photo.jpg');
await s3.send(
new PutObjectCommand({
Bucket: 'my-bucket',
Key: 'photo.jpg',
Body: body,
ContentType: 'image/jpeg',
CacheControl: 'public, max-age=31536000',
}),
);
For large files, prefer the Upload helper from @aws-sdk/lib-storage:
import { Upload } from '@aws-sdk/lib-storage';
import { createReadStream } from 'node:fs';
const upload = new Upload({
client: s3,
params: {
Bucket: 'my-bucket',
Key: 'video.mp4',
Body: createReadStream('./video.mp4'),
ContentType: 'video/mp4',
},
partSize: 8 * 1024 * 1024, // 8 MB
queueSize: 4,
});
upload.on('httpUploadProgress', (p) => {
console.log(`${p.loaded} / ${p.total}`);
});
await upload.done();
Upload switches to multipart automatically once the body exceeds 5 MB and parallelizes parts up to queueSize.
List objects
import { ListObjectsV2Command } from '@aws-sdk/client-s3';
let continuationToken: string | undefined;
do {
const result = await s3.send(
new ListObjectsV2Command({
Bucket: 'my-bucket',
Prefix: 'photos/',
MaxKeys: 1000,
ContinuationToken: continuationToken,
}),
);
for (const obj of result.Contents ?? []) {
console.log(obj.Key, obj.Size);
}
continuationToken = result.NextContinuationToken;
} while (continuationToken);
Download an object
import { GetObjectCommand } from '@aws-sdk/client-s3';
import { writeFile } from 'node:fs/promises';
const { Body } = await s3.send(
new GetObjectCommand({ Bucket: 'my-bucket', Key: 'photo.jpg' }),
);
const bytes = await Body!.transformToByteArray();
await writeFile('downloaded.jpg', bytes);
To stream straight to a file:
import { createWriteStream } from 'node:fs';
import { pipeline } from 'node:stream/promises';
await pipeline(
Body as NodeJS.ReadableStream,
createWriteStream('downloaded.jpg'),
);
Delete an object
import { DeleteObjectCommand } from '@aws-sdk/client-s3';
await s3.send(
new DeleteObjectCommand({ Bucket: 'my-bucket', Key: 'photo.jpg' }),
);
Bulk delete:
import { DeleteObjectsCommand } from '@aws-sdk/client-s3';
await s3.send(
new DeleteObjectsCommand({
Bucket: 'my-bucket',
Delete: {
Objects: [{ Key: 'a.jpg' }, { Key: 'b.jpg' }, { Key: 'c.jpg' }],
},
}),
);
Pre-signed URLs
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { GetObjectCommand, PutObjectCommand } from '@aws-sdk/client-s3';
// Read URL — give the recipient 1-hour download access
const downloadUrl = await getSignedUrl(
s3,
new GetObjectCommand({ Bucket: 'my-bucket', Key: 'private.pdf' }),
{ expiresIn: 3600 },
);
// Write URL — let a browser upload an object directly
const uploadUrl = await getSignedUrl(
s3,
new PutObjectCommand({
Bucket: 'uploads',
Key: `user-${userId}/${filename}`,
ContentType: 'image/jpeg',
}),
{ expiresIn: 600 },
);
See pre-signed URLs for more.
Error handling
import { S3ServiceException } from '@aws-sdk/client-s3';
try {
await s3.send(new GetObjectCommand({ Bucket, Key }));
} catch (err) {
if (err instanceof S3ServiceException) {
if (err.name === 'NoSuchKey') {
// handle missing object
} else {
console.error(err.name, err.message, err.$metadata.requestId);
}
} else {
throw err;
}
}
Browser usage
The same SDK runs in the browser. Use it for read-only access to public buckets, or for issuing pre-signed-URL-driven uploads. Never embed your secret access key in client code — always generate pre-signed URLs server-side.
TypeScript types
@aws-sdk/client-s3 ships with types out of the box. All command inputs and outputs are fully typed.