# Cloudflare R2 (https://v1.s3.dimah.dev/docs/providers/cloudflare-r2)

Cloudflare R2 supports the S3 API with two important differences: presigned
uploads must use `PUT`, and object ACLs are ignored.

## 1. Configure upload method [#1-configure-upload-method]

Set `upload: { method: "PUT" }`:

```ts title="lib/s3.ts"
import { S3Client } from "@aws-sdk/client-s3";
import { dimahS3, route } from "@dimah-s3/server";

export const awsS3 = new S3Client({
  region: "auto",
  endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
  credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY_ID!,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
  },
});

export const s3 = dimahS3({
  client: awsS3,
  bucket: process.env.R2_BUCKET!,
  routes: {
    avatar: route({
      upload: {
        method: "PUT", // Required for Cloudflare R2 // [!code ++]
        fileTypes: ["image/*"],
        maxFileSize: 2 * 1024 * 1024,
      },
    }),
  },
});
```

## 2. Bucket CORS policy [#2-bucket-cors-policy]

Add a CORS rule in the Cloudflare R2 dashboard for your frontend domain:

```json
[
  {
    "AllowedOrigins": ["https://your-app.example"],
    "AllowedMethods": ["GET", "PUT", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag", "Content-Type"],
    "MaxAgeSeconds": 3000
  }
]
```

## Frequently asked questions [#frequently-asked-questions]

<Accordions>

<Accordion title="How do I serve R2 files publicly?">

Enable public access for the bucket or connect a custom domain such as
`cdn.example.com`. Then build URLs from that public base URL and the
server-issued object key; [`buildPublicObjectUrl`](https://v1.s3.dimah.dev/docs/react/helpers#checksums-and-public-urls)
handles URL encoding for you.

</Accordion>

</Accordions>
