Skip to main content

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
PackageWhat it's for
@aws-sdk/client-s3The core S3 client and command classes
@aws-sdk/lib-storageHigh-level uploader (handles multipart automatically)
@aws-sdk/s3-request-presignerPre-signed URL generation

Initialize the client

src/filebase.ts
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.

What's next