S3-compatible storage adapter for @arraypress/storage. Works with AWS S3, Cloudflare R2 (via S3 API), MinIO, DigitalOcean Spaces, and any S3-compatible service.
Works in Node.js, Cloudflare Workers, Deno, Bun, and any runtime that supports the AWS SDK.
npm install @arraypress/storage-s3 @arraypress/storageThis package depends on @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner (installed automatically).
import { createS3Storage } from '@arraypress/storage-s3';
const storage = createS3Storage({
bucket: 'my-bucket',
region: 'us-east-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
publicUrl: 'https://my-bucket.s3.amazonaws.com',
});
// Upload
await storage.upload({
key: 'uploads/photo.jpg',
body: fileBuffer,
contentType: 'image/jpeg',
});
// Download
const file = await storage.download('uploads/photo.jpg');
if (file) {
console.log(file.contentType); // 'image/jpeg'
console.log(file.size); // bytes
}
// Signed URLs (for direct client uploads)
const signed = await storage.getSignedUploadUrl({
key: 'uploads/new-file.jpg',
contentType: 'image/jpeg',
expiresIn: 3600,
});
console.log(signed.url); // Pre-signed URL for PUTUse this adapter when you need signed URLs with R2 (the native R2 bindings have limited presigned URL support).
import { createS3Storage } from '@arraypress/storage-s3';
const storage = createS3Storage({
bucket: 'my-bucket',
region: 'auto',
endpoint: 'https://ACCOUNT_ID.r2.cloudflarestorage.com',
accessKeyId: env.R2_ACCESS_KEY_ID,
secretAccessKey: env.R2_SECRET_ACCESS_KEY,
publicUrl: 'https://media.mystore.com',
});import { createS3Storage } from '@arraypress/storage-s3';
const storage = createS3Storage({
bucket: 'my-bucket',
region: 'us-east-1',
endpoint: 'http://localhost:9000',
accessKeyId: 'minioadmin',
secretAccessKey: 'minioadmin',
forcePathStyle: true, // Required for MinIO
});import { Hono } from 'hono';
import { createS3Storage } from '@arraypress/storage-s3';
const app = new Hono();
app.post('/upload', async (c) => {
const storage = createS3Storage({
bucket: 'my-bucket',
region: 'us-east-1',
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
});
const body = await c.req.arrayBuffer();
const result = await storage.upload({
key: `uploads/${Date.now()}.jpg`,
body: new Uint8Array(body),
contentType: 'image/jpeg',
});
return c.json(result);
});const mpu = await storage.createMultipartUpload('large-file.zip', {
contentType: 'application/zip',
});
const part1 = await mpu.uploadPart(1, chunk1);
const part2 = await mpu.uploadPart(2, chunk2);
await mpu.complete([part1, part2]);Creates a Storage adapter backed by any S3-compatible service.
| Option | Type | Required | Description |
|---|---|---|---|
bucket |
string |
Yes | S3 bucket name |
region |
string |
Yes | AWS region (e.g. 'us-east-1'). Use 'auto' for R2. |
endpoint |
string |
No | S3-compatible endpoint URL |
accessKeyId |
string |
Yes | AWS access key ID |
secretAccessKey |
string |
Yes | AWS secret access key |
publicUrl |
string |
No | Public URL prefix for getPublicUrl() |
forcePathStyle |
boolean |
No | Force path-style URLs (required for MinIO). Default: false. |
StorageinterfaceStorageErrorclasscontentHash(),contentAddressedKey(),safeDisposition()helpers- All type definitions
MIT