# S3 Destination (AWS S3 / MinIO / R2)

## Config block

```yaml
destination:
  type: s3
  bucket: my-data-bucket            # S3 bucket name (must already exist)
  prefix: exports/daily/            # optional key prefix (folder-like path)
  region: us-east-1                 # AWS region (required for AWS S3)
```

## Credentials

Rivet uses [OpenDAL](https://opendal.apache.org/) for S3 access. Credentials are resolved in this order:

### Option 1: AWS default credential chain (recommended)

If you're running on EC2, ECS, Lambda, or have `~/.aws/credentials` configured, just set `region`:

```yaml
destination:
  type: s3
  bucket: my-data-bucket
  region: us-east-1
```

### Option 2: Environment variables

Set `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` before running:

```bash
export AWS_ACCESS_KEY_ID=AKIA...
export AWS_SECRET_ACCESS_KEY=wJa...
rivet run --config export.yaml
```

Or reference them in the config:

```yaml
destination:
  type: s3
  bucket: my-data-bucket
  region: us-east-1
  access_key_env: AWS_ACCESS_KEY_ID
  secret_key_env: AWS_SECRET_ACCESS_KEY
```

### Option 3: AWS profile

```yaml
destination:
  type: s3
  bucket: my-data-bucket
  region: us-east-1
  aws_profile: my-profile           # uses [my-profile] from ~/.aws/credentials
```

## S3-compatible endpoints (MinIO, R2, Wasabi)

For non-AWS S3-compatible services, add `endpoint`:

```yaml
# MinIO
destination:
  type: s3
  bucket: rivet-exports
  endpoint: "http://localhost:9000"
  region: us-east-1                 # required but can be any value
  access_key_env: MINIO_ACCESS_KEY
  secret_key_env: MINIO_SECRET_KEY

# Cloudflare R2
destination:
  type: s3
  bucket: my-r2-bucket
  endpoint: "https://ACCOUNT_ID.r2.cloudflarestorage.com"
  region: auto
  access_key_env: R2_ACCESS_KEY
  secret_key_env: R2_SECRET_KEY
```

## Anonymous access

For public or pre-configured buckets (e.g. MinIO in dev):

```yaml
destination:
  type: s3
  bucket: public-bucket
  endpoint: "http://localhost:9000"
  region: us-east-1
  allow_anonymous: true
```

## Output keys

Files are uploaded as:

```
s3://{bucket}/{prefix}{export_name}_{YYYYMMDD}_{HHMMSS}.{format}
```

Example: `s3://my-data-bucket/exports/daily/orders_20260406_120000.parquet`

## Streaming upload

Rivet streams data directly to S3 without buffering the entire file in memory. Peak RSS stays proportional to `batch_size`, not to the total export size.

## Verify

```bash
rivet doctor --config export.yaml
```

Output:

```
[OK] Destination 's3://my-data-bucket/exports/daily/' — bucket accessible, write test passed
```

## Troubleshooting

**`NoSuchBucket`** -- The bucket must already exist. Create it first: `aws s3 mb s3://my-data-bucket`.

**`AccessDenied`** -- Check IAM policy. Rivet needs `s3:PutObject` and `s3:GetBucketLocation`.

**`SignatureDoesNotMatch` with MinIO** -- Ensure `region` is set (even for MinIO, e.g. `us-east-1`).
