S3 Adapter
Store blobs in S3-compatible object storage with multipart uploads, presigned URLs, and R2 support.
Overview
The S3 adapter handles binary object storage. It supports AWS S3, Cloudflare R2, MinIO, and any S3-compatible service. Use it for files, images, backups, and other large binary data that does not fit well in SQLite or Postgres.
Bucket configuration
import { createStore } from "@cuitty/persist";
const store = await createStore("assets", {
adapter: "s3",
s3: {
bucket: "my-app-assets",
region: "us-east-1",
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
},
},
});
For Cloudflare R2, set the endpoint to your R2 URL:
const store = await createStore("assets", {
adapter: "s3",
s3: {
bucket: "my-app-assets",
region: "auto",
endpoint: "https://<account-id>.r2.cloudflarestorage.com",
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID,
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
},
},
});
Multipart uploads
Files larger than 5 MB are automatically uploaded using S3 multipart upload. Persist splits the file into 8 MB parts and uploads them in parallel. If an upload is interrupted, partial parts are cleaned up automatically.
// Large file upload — multipart happens transparently
const buffer = await fs.readFile("./backup.tar.gz"); // 500 MB
await store.blobs.put("backups/2026-05-11.tar.gz", buffer);
You can configure the part size and concurrency:
const store = await createStore("assets", {
adapter: "s3",
s3: {
bucket: "my-app-assets",
multipart: {
partSize: 16 * 1024 * 1024, // 16 MB parts
concurrency: 4,
},
},
});
Presigned URLs
Generate temporary URLs that grant time-limited access to a blob without exposing credentials.
const url = await store.blobs.presign("reports/q1.pdf", {
expiresIn: 3600, // 1 hour
method: "GET",
});
// Share `url` with a client — no credentials needed
Supported store classes
The S3 adapter supports blobs only. For records, events, and kv, pair it with the SQLite or Postgres adapter. Persist supports using multiple adapters in a single application, each backing a different store.