Providers

AWS S3

Set up AWS S3 for production file uploads in under 5 minutes

AWS S3 Setup

Get AWS S3 configured for production file uploads in under 5 minutes. This guide covers everything from bucket creation to security best practices.

Why AWS S3? The most trusted object storage service with 99.999999999% durability, global CDN integration, and predictable pricing. Perfect for applications that need reliable, scalable file storage.

What You'll Accomplish

By the end of this guide, you'll have:

  • ✅ A secure S3 bucket configured for web uploads
  • ✅ IAM user with minimal required permissions
  • ✅ CORS configuration for your domain
  • ✅ Environment variables ready for production
  • ✅ Cost optimization settings enabled

Create AWS Account & S3 Bucket

If you don't have an AWS account, sign up for free - you get 5GB of S3 storage free for 12 months.

  1. Open S3 Console: Go to S3 Console
  2. Create Bucket: Click "Create bucket"
  3. Configure Basic Settings:
Bucket name: your-app-uploads-prod
Region: us-east-1 (or closest to your users)

Bucket Naming: Use a unique, descriptive name. Bucket names are global across all AWS accounts and cannot be changed later.

  1. Block Public Access: Keep all "Block public access" settings enabled (this is secure - we'll use presigned URLs)
  2. Enable Versioning: Recommended for data protection
  3. Create Bucket: Click "Create bucket"

Configure CORS for Web Access

Your web application needs permission to upload files directly to S3.

  1. Open Your Bucket: Click on your newly created bucket
  2. Go to Permissions Tab: Click "Permissions"
  3. Edit CORS Configuration: Scroll to "Cross-origin resource sharing (CORS)" and click "Edit"
  4. Add CORS Rules:
[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
    "AllowedOrigins": [
      "http://localhost:3000",
      "http://localhost:3001",
      "https://localhost:3000"
    ],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }
]
[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
    "AllowedOrigins": [
      "https://yourdomain.com",
      "https://www.yourdomain.com",
      "https://staging.yourdomain.com"
    ],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 86400
  }
]
  1. Save Changes: Click "Save changes"

Security Note: Only add origins you trust. Wildcards (*) should never be used in production - they allow any website to upload to your bucket.

Create IAM User with Minimal Permissions

Create a dedicated user for your application with only the permissions it needs.

  1. Open IAM Console: Go to IAM Console
  2. Create User:
    • Click "Users" → "Create user"
    • Username: your-app-s3-user
    • Select "Programmatic access" only
  3. Create Custom Policy:
    • Click "Attach policies directly"
    • Click "Create policy"
    • Use JSON editor and paste:
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::your-app-uploads-prod/*"
    },
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::your-app-uploads-prod"
    }
  ]
}
  1. Name the Policy: YourApp-S3-Upload-Policy
  2. Attach to User: Go back to user creation and attach your new policy
  3. Create User: Complete the user creation

Replace Bucket Name: Make sure to replace your-app-uploads-prod with your actual bucket name in the policy JSON.

Get Access Keys

Your application needs these credentials to generate presigned URLs.

  1. Select Your User: In IAM Users, click on your newly created user
  2. Security Credentials Tab: Click "Security credentials"
  3. Create Access Key:
    • Click "Create access key"
    • Select "Application running outside AWS"
    • Click "Next"
  4. Copy Credentials:
    • Access Key ID: Copy this value
    • Secret Access Key: Copy this value (you'll only see it once!)

Security Alert: Never commit these keys to version control or share them publicly. Use environment variables or secure key management services.

Configure Environment Variables

Add your AWS credentials to your application.

# .env.local
AWS_ACCESS_KEY_ID=your_access_key_id
AWS_SECRET_ACCESS_KEY=your_secret_access_key
AWS_REGION=us-east-1
AWS_S3_BUCKET_NAME=your-app-uploads-prod

# Optional: Enable S3 debug logging

DEBUG=aws-sdk:\*
# Use your hosting platform's environment variable system
# Never store production keys in .env files

# Vercel:
# vercel env add AWS_ACCESS_KEY_ID
# vercel env add AWS_SECRET_ACCESS_KEY

# Netlify:
# Add in Site settings > Environment variables

# Railway:
# Add in Variables tab

AWS_ACCESS_KEY_ID=your_access_key_id
AWS_SECRET_ACCESS_KEY=your_secret_access_key
AWS_REGION=us-east-1
AWS_S3_BUCKET_NAME=your-app-uploads-prod

Test Your Configuration

Verify everything works by testing an upload.

  1. Start Your App: Run your development server
  2. Test Upload: Try uploading a file using your upload component
  3. Check S3: Verify the file appears in your S3 bucket
  4. Check Access: Verify you can access the uploaded file via its URL

If something's not working:

  • ✅ Check CORS configuration matches your domain
  • ✅ Verify IAM policy has correct bucket name
  • ✅ Confirm environment variables are loaded
  • ✅ Check browser console for specific error messages

🎉 Congratulations!

Your AWS S3 bucket is now ready for production! Here's what you've accomplished:

  • Secure Storage: Files are stored in AWS's enterprise-grade infrastructure
  • Cost Efficient: Pay only for what you use, with free tier coverage
  • Globally Accessible: Files available worldwide with low latency
  • Scalable: Handles millions of files without configuration changes
  • Secure Access: Minimal IAM permissions and proper CORS setup

💰 Cost Optimization

Keep your AWS bills low with these optimization tips:

Storage Classes

# Standard: $0.023 per GB/month - for frequently accessed files
# Standard-IA: $0.0125 per GB/month - for infrequently accessed files
# Glacier: $0.004 per GB/month - for archival (retrieval takes hours)

Lifecycle Policies

Set up automatic transitions to save money:

  1. Go to Your Bucket → Management → Lifecycle rules
  2. Create Rule:
    • Transition to Standard-IA after 30 days
    • Transition to Glacier after 90 days
    • Delete incomplete multipart uploads after 1 day

Request Optimization

  • Use CloudFront: Cache files globally to reduce S3 requests
  • Batch Operations: Group multiple operations when possible
  • Monitor Usage: Set up billing alerts for unexpected costs

🔒 Security Best Practices

Access Control

// Example: User-specific upload paths
{
  "prefix": "users/${user.id}/*",
  "maxFileSize": "10MB",
      "types": ["image/jpeg", "image/png"]
}

Monitoring

  1. Enable CloudTrail: Track all S3 API calls
  2. Set Up Alerts: Monitor unusual access patterns
  3. Regular Audits: Review IAM permissions quarterly

Backup Strategy

# Cross-region replication for critical data
Source Bucket: us-east-1
Replica Bucket: us-west-2
Replication: Real-time

🚀 What's Next?

Now that AWS S3 is configured, explore these advanced features:

📈 CloudFront CDN

Speed up file delivery globally with AWS CloudFront

CloudFront Setup →

🔄 Lambda Processing

Automatically resize images and process files

Lambda Integration →

📊 Analytics & Monitoring

Track upload metrics and usage patterns

Monitoring Guide →

🔐 Advanced Security

Implement encryption, access logging, and compliance

Security Guide →

💡 Pro Tips

Naming Convention: Use consistent bucket naming like {company}-{app}- {environment}-uploads for easy management across multiple projects.

Cost Alert: Set up AWS billing alerts at $5, $20, and $50 to avoid surprise charges during development.

Performance: Place your S3 bucket in the same region as your application server for fastest presigned URL generation.


Need help with AWS S3 setup? Join our Discord community or check out the troubleshooting guide for common issues.