> For the complete documentation index, see [llms.txt](https://mercure-technologies.gitbook.io/xprem/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mercure-technologies.gitbook.io/xprem/3-0-x/storage/s3-storage.md).

# S3 Storage

Use Amazon S3 or an S3-compatible provider to store update assets.

### Configure Amazon S3

Set the bucket and AWS Region:

```dotenv
STORAGE_MODE=s3
AWS_REGION=your-region
S3_BUCKET_NAME=your-bucket-name
```

### Configure S3-compatible storage

For Cloudflare R2, MinIO, DigitalOcean Spaces, or [Railway storage buckets](https://docs.railway.com/storage-buckets), set the provider endpoint:

```dotenv
STORAGE_MODE=s3
AWS_REGION=auto
AWS_BASE_ENDPOINT=https://account-id.r2.cloudflarestorage.com
S3_BUCKET_NAME=your-bucket-name
```

{% hint style="info" %}
If the provider requires path-style addressing, also set:
{% endhint %}

```shellscript
AWS_S3_FORCE_PATH_STYLE=true
```

### Authenticate requests

Amazon S3 supports AWS IAM roles. For Amazon EKS, use IAM Roles for Service Accounts (IRSA).

If you do not use an IAM role, provide access keys:

```dotenv
AWS_ACCESS_KEY_ID=your-access-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
```

{% hint style="warning" %}
Use the equivalent identity mechanism for S3-compatible storage. This IAM role configuration applies only to AWS.
{% endhint %}

### Recommended AWS IAM role

Use a dedicated EKS service account named `expo-open-ota-sa`. Attach one of these permission policies to its IAM role.

{% tabs %}
{% tab title="Without BUCKET\_KEY\_PREFIX" %}

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::YOUR_BUCKET"
    },
    {
      "Sid": "ObjectRW",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::YOUR_BUCKET/*"
    }
  ]
}
```

Replace `YOUR_BUCKET` with your bucket name.
{% endtab %}

{% tab title="With BUCKET\_KEY\_PREFIX" %}

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::YOUR_BUCKET",
      "Condition": {
        "StringLike": {
          "s3:prefix": "myprefix/*"
        }
      }
    },
    {
      "Sid": "ObjectRW",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::YOUR_BUCKET/myprefix/*"
    }
  ]
}
```

Replace `YOUR_BUCKET` and `myprefix` with your bucket and `BUCKET_KEY_PREFIX` value.
{% endtab %}
{% endtabs %}

The role can manage update objects in the configured prefix or entire bucket.

### Asset delivery

With CloudFront configured, the server returns CloudFront-signed URLs. With the generic CDN, it returns plain public CDN URLs.

Without a CDN, the server returns the asset directly.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mercure-technologies.gitbook.io/xprem/3-0-x/storage/s3-storage.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
