Skip to main content

Prerequisites

  • AWS account with S3 access
  • IAM user with S3 permissions

1. Create S3 Bucket

  1. Go to AWS S3 Console
  2. Click Create bucket
  3. Configure:
    • Bucket name: your-app-uploads (must be globally unique)
    • Region: Choose closest to your users
    • Block Public Access: Keep enabled (we use presigned URLs)
  4. Click Create bucket

CORS Configuration

Add this CORS policy to your bucket:
The ExposeHeaders: ["ETag"] is required for multipart uploads to work correctly.

2. Create IAM User

  1. Go to IAM Console
  2. Create a new user with Programmatic access
  3. Attach this policy:
  1. Save the Access Key ID and Secret Access Key

3. Environment Variables

Add these to your backend .env:

4. API Endpoints

The upload router (apps/api/src/routers/upload.ts) provides these endpoints:

Simple Upload

Multipart Upload

5. Database Schema

The File model tracks uploads:

6. Storage Quota

Configure per-user storage limits in upload.ts:

Security Considerations

URLs expire after 1 hour by default. Adjust expiresIn in s3.ts if needed.
Allowed MIME types are configured in ALLOWED_MIME_TYPES. Add/remove as needed.
Consider adding rate limiting to upload endpoints in production.
For user-generated content, consider AWS Lambda + ClamAV for scanning.

Test Checklist

  • API starts without S3 errors
  • requestUploadUrl returns a presigned URL
  • Uploaded file can be confirmed in the database

Troubleshooting

If uploads fail, re-check S3 credentials and bucket CORS settings.

Remove / Disable

To disable uploads while you configure S3, set: apps/mobile/features/feature-registry.tsxfeatureFlags.fileUploads = false For production removal guidance, see Removing Features.