Framework guides
Node.js
Use Quat with the AWS SDK for JavaScript v3.
Install
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner dotenv
Environment
S3_ENDPOINT=https://storage.example.local
S3_ACCESS_KEY=your-access-key
S3_SECRET_KEY=your-secret-key
S3_REGION=us-east-1
S3_BUCKET=my-bucket
S3_USE_PATH_STYLE_ENDPOINT=true
Client
import "dotenv/config";
import { S3Client } from "@aws-sdk/client-s3";
export const s3 = new S3Client({
endpoint: process.env.S3_ENDPOINT,
region: process.env.S3_REGION || "us-east-1",
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY || "",
secretAccessKey: process.env.S3_SECRET_KEY || "",
},
forcePathStyle: process.env.S3_USE_PATH_STYLE_ENDPOINT !== "false",
});
export const bucket = process.env.S3_BUCKET || "";
Upload Object
import { readFile } from "node:fs/promises";
import { PutObjectCommand } from "@aws-sdk/client-s3";
import { bucket, s3 } from "./s3";
export async function uploadObject() {
const body = await readFile("./avatar.png");
await s3.send(
new PutObjectCommand({
Bucket: bucket,
Key: "users/123/avatar.png",
Body: body,
ContentType: "image/png",
}),
);
console.log("Uploaded users/123/avatar.png");
}
Download Object
import { writeFile } from "node:fs/promises";
import { GetObjectCommand } from "@aws-sdk/client-s3";
import { bucket, s3 } from "./s3";
export async function downloadObject() {
const response = await s3.send(
new GetObjectCommand({
Bucket: bucket,
Key: "users/123/avatar.png",
}),
);
if (!response.Body) throw new Error("Object body was empty");
const bytes = await response.Body.transformToByteArray();
await writeFile("./downloaded-avatar.png", bytes);
}
List Objects
import { ListObjectsV2Command } from "@aws-sdk/client-s3";
import { bucket, s3 } from "./s3";
export async function listObjects() {
const response = await s3.send(
new ListObjectsV2Command({
Bucket: bucket,
Prefix: "users/123/",
}),
);
for (const item of response.Contents || []) {
console.log(item.Key, item.Size);
}
}
Delete Object
import { DeleteObjectCommand } from "@aws-sdk/client-s3";
import { bucket, s3 } from "./s3";
export async function deleteObject() {
await s3.send(
new DeleteObjectCommand({
Bucket: bucket,
Key: "users/123/avatar.png",
}),
);
}
Presigned URL
The customer app code includes backend-generated upload intents and download links. If your Quat storage endpoint accepts standard S3 signed requests, you can generate SDK presigned URLs:
import { GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { bucket, s3 } from "./s3";
export async function createDownloadUrl() {
return getSignedUrl(
s3,
new GetObjectCommand({
Bucket: bucket,
Key: "users/123/avatar.png",
}),
{ expiresIn: 900 },
);
}
Note: Verify presigned URL support against your deployment. This repository confirms console download links, but does not include the full storage server implementation.
Common Node.js Errors
| Error | Fix |
|---|---|
SignatureDoesNotMatch | Check endpoint, region, keys, and forcePathStyle. |
InvalidAccessKeyId | Reveal or regenerate keys in Quat and update .env. |
NoSuchBucket | Use the real bucket name, not only the friendly name. |
| DNS error with bucket subdomain | Set forcePathStyle: true. |