# Amazon S3 (https://s3.dimah.dev/docs/providers/aws-s3)



Amazon S3 is fully supported with all native features (presigned POST, presigned PUT, object ACLs, and multipart uploads).

<div className="fd-steps">
  <div className="fd-step">
    ## Bucket CORS configuration [#1-bucket-cors-configuration]

    Because uploads occur directly from the browser to your AWS S3 bucket, you must configure a CORS policy on your S3 bucket:

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

  <div className="fd-step">
    ## Server configuration [#2-server-configuration]

    ```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: process.env.S3_REGION!,
      credentials: {
        accessKeyId: process.env.S3_ACCESS_KEY_ID!,
        secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
      },
    });

    export const s3 = dimahS3({
      client: awsS3,
      bucket: process.env.S3_BUCKET!,
      routes: {
        avatar: route({
          upload: {
            fileTypes: ["image/*"],
            maxFileSize: 2 * 1024 * 1024,
          },
        }),
      },
    });
    ```
  </div>
</div>

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

<Accordions>
  <Accordion title="How do I make uploaded files publicly accessible?">
    Set `upload: { acl: "public-read" }` in your route definition (ensure Object Ownership and ACLs are enabled in your S3 bucket settings):

    ```ts
    avatar: route({
      upload: {
        acl: "public-read",
        fileTypes: ["image/*"],
        maxFileSize: 2 * 1024 * 1024,
      },
    });
    ```
  </Accordion>

  <Accordion title="How do I troubleshoot 403 Forbidden CORS errors?">
    Ensure `AllowedOrigins` includes your frontend port (e.g. `http://localhost:3000`) and that `ExposeHeaders` contains `ETag` and `Content-Type`.
  </Accordion>
</Accordions>
