2.0 beta — new releases can include breaking changes. Stable 1.x docs
dimah-s3v2.0.0-beta.0
Providers

Providers

Configure Amazon S3, Cloudflare R2, MinIO, and other S3-compatible storage.

dimah-s3 talks to storage through the AWS SDK S3Client. Any service that speaks enough of the S3 API can work — Amazon S3, Cloudflare R2, MinIO, and similar backends.

S3-compatible is not the same as Amazon S3. Providers skip or ignore parts of the API. With a presign-first stack, those gaps show up quickly: the browser hits storage directly, so CORS, addressing, and the upload method have to match what the provider actually supports.

TopicWhy it matters
Presigned PUT vs POSTDefault upload is PUT. POST is opt-in, and some providers have no presigned POST.
SDK checksumsThe S3Client must set requestChecksumCalculation: "WHEN_REQUIRED", or presigned uploads fail.
Object ACLacl: "public-read" needs real ACL support. Others use bucket policies or a public-access toggle.
Endpoint & addressingCustom endpoints often need endpoint, and sometimes forcePathStyle: true.
CORSBrowser uploads hit storage directly. The bucket must allow your origin, methods, and headers.
Public URLsPublic reads may use a CDN, a custom domain, or *.r2.dev — not object ACL.

Wire the shared client once in Quickstart. Use the guides below only for the extras that defaults do not cover.

Comparison

AWS S3Cloudflare R2MinIO
Presigned PUTYes (default)Yes (default)Yes (default)
Presigned POSTYesNoYes
Object ACLYesIgnoredUse policies
Custom endpointOptionalRequiredRequired
forcePathStyleUsually offOffTypically on

Configuration

import { S3Client } from "@aws-sdk/client-s3";
import { dimahS3, route } from "@dimah-s3/server";

export const awsS3 = new S3Client({
  // region, endpoint, credentials …
  requestChecksumCalculation: "WHEN_REQUIRED", 
});

export const s3 = dimahS3({
  client: awsS3,
  bucket: process.env.S3_BUCKET!,
  routes: {
    avatar: route({
      upload: { method: "POST" }, 
    }),
  },
});

The default upload method is PUT, which every provider here supports. Switch to POST only when you want a form upload and the provider has presigned POST. Confirm reports the ACL from upload.acl or object; there is no GetObjectAcl lookup.

Client hooks and @dimah-s3/ui read method from the presign response. Change it on the server only.

Guides

On this page