javascript
AWS SDK for JavaScript v3
Install
npm install @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presignerConfigure
Configure the endpoint, region, credential and bucket in this tool’s vocabulary. Path-style addressing is recommended for dotted bucket names and clients without nested wildcard TLS, but virtual-hosted addressing is also supported.
| In AWS SDK for JavaScript v3 | Set it to |
|---|---|
| endpoint | https://s3.canada.popcloud.ca |
| region | canada |
| credentials.accessKeyId | PCAK00EXAMPLEKEYID00 |
| credentials.secretAccessKey | <your secret access key> |
| forcePathStyle | true |
export AWS_ACCESS_KEY_ID=PCAK00EXAMPLEKEYID00
export AWS_SECRET_ACCESS_KEY=<your secret access key>
export AWS_ENDPOINT_URL=https://s3.canada.popcloud.ca
export AWS_REGION=canada
export POPCLOUD_BUCKET=pc-your-org-mediaThese are example values. Sign in and every snippet on this site fills in with your own endpoint, key and bucket.
import { S3Client } from "@aws-sdk/client-s3";
const s3 = new S3Client({
endpoint: process.env.AWS_ENDPOINT_URL, // https://s3.<region>.popcloud.ca
region: process.env.AWS_REGION, // canada
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
// Recommended for predictable custom-endpoint behavior. Virtual-hosted
// requests are supported too for ordinary single-label bucket names.
forcePathStyle: true,
});Use it
Upload an object
await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: body,
ContentType: "text/plain",
}),
);Upload a large object
// Handles multipart, concurrency and retries for you — use it for anything
// whose size you do not control.
const upload = new Upload({
client: s3,
params: { Bucket: bucket, Key: key, Body: body },
queueSize: 4,
partSize: 8 * 1024 * 1024,
});
upload.on("httpUploadProgress", (p) => console.log(`${p.loaded}/${p.total ?? "?"}`));
await upload.done();Download an object
const object = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key }));
const text = await object.Body.transformToString();List a prefix
for await (const page of paginateListObjectsV2(
{ client: s3 },
{ Bucket: bucket, Prefix: prefix },
)) {
for (const object of page.Contents ?? []) {
keys.push(object.Key);
}
}Presign a URL
const url = await getSignedUrl(
s3,
new GetObjectCommand({ Bucket: bucket, Key: key }),
{ expiresIn: 3600 }, // seconds; 7 days is the hard maximum
);
// Anyone holding this URL can read the object until it expires, with no
// credentials at all.Delete an object
await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));What to watch for
These apply to AWS SDK for JavaScript v3 specifically. The full list covers the platform.
- You’ll see
- A GET carrying If-None-Match, If-Match or If-Modified-Since returns 400 InvalidRequest. Expected behaviour is 304 Not Modified for a cache hit and 412 PreconditionFailed for a stale precondition.
- Why
- The conditional headers are not handled correctly on the read path. This is a defect, not a design decision.
- Instead
- Do not send conditional headers on GET. If you are putting a CDN in front of a bucket, cache on a fixed TTL rather than on revalidation, and version your object keys so a new key means new content. Conditional *writes* (If-None-Match on PUT) are separately unsupported.
- You’ll see
- 405 MethodNotAllowed from CreateBucket or DeleteBucket — `aws s3 mb`, `mc mb`, or a tool provisioning its own bucket on first run.
- Why
- Bucket lifecycle belongs to the control plane, which also allocates the storage account, the data-plane key and the CORS rules that come with it. Letting the edge create buckets would create half of one.
- Instead
- Create buckets in the dashboard, or with `POST /v1/buckets` on the control-plane API. Everything object-level then works normally against that bucket.
How this page is kept true
Every snippet above was extracted from examples/node/aws-sdk-js-v3, a program that uploads, downloads, compares bytes, lists, presigns and cleans up after itself. It runs in CI against a live sandbox organisation via make docs-verify-node. If it stops passing, this page is wrong and we treat that as a bug in the product.
Not yet run against the live sandbox — the runner is wired, the first verified run stamps this line.