# Providers (https://s3.dimah.dev/docs/providers)



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.

| Topic                 | Why it matters                                                                                     |
| --------------------- | -------------------------------------------------------------------------------------------------- |
| Presigned POST vs PUT | Default upload is POST. Some providers only accept PUT.                                            |
| Object ACL            | `acl: "public-read"` needs real ACL support. Others use bucket policies or a public-access toggle. |
| Endpoint & addressing | Custom endpoints often need `endpoint`, and sometimes `forcePathStyle: true`.                      |
| CORS                  | Browser uploads hit storage directly. The bucket must allow your origin, methods, and headers.     |
| Public URLs           | Public reads may use a CDN, a custom domain, or `*.r2.dev` — not object ACL.                       |

Wire the shared client once in [Quickstart](https://s3.dimah.dev/docs/quickstart). Use the guides
below only for the extras that defaults do not cover.

## Comparison [#comparison]

|                   | [AWS S3](https://s3.dimah.dev/docs/providers/aws-s3) | [Cloudflare R2](https://s3.dimah.dev/docs/providers/cloudflare-r2) | [MinIO](https://s3.dimah.dev/docs/providers/minio) |
| ----------------- | :------------------------------: | :--------------------------------------------: | :----------------------------: |
| Presigned POST    |                Yes               |                       No                       |               Yes              |
| Presigned PUT     |                Yes               |                 Yes (required)                 |               Yes              |
| Object ACL        |                Yes               |                     Ignored                    |          Use policies          |
| Custom `endpoint` |             Optional             |                    Required                    |            Required            |
| `forcePathStyle`  |            Usually off           |                       Off                      |            Required            |

## Configuration [#configuration]

```ts
import { dimahS3, route } from "@dimah-s3/server";

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

The default upload method is POST. Switch to PUT when the provider has no
Presigned POST (R2 is the usual case). ACL on confirm comes from
`upload.acl` / `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 [#guides]

<Cards>
  <Card title="Amazon S3" href="/docs/providers/aws-s3" description="Defaults work. Configure bucket CORS for browser uploads." />

  <Card title="Cloudflare R2" href="/docs/providers/cloudflare-r2" description="PUT uploads, the R2 endpoint, and bucket CORS." />

  <Card title="MinIO" href="/docs/providers/minio" description="Path-style addressing and server CORS for self-hosted S3." />
</Cards>
