iconSuperDir

Image Upload

How to configure the image upload.

In SuperDir, for image uploads (avatar, project images, project logo), we use uploadthing as the default storage provider. It's free (2G/month) for small projects.

Uploadthing Configuration

If you want to keep using uploadthing as your storage provider, the integration is pretty easy.

Create an account and get an API key

Create an account on uploadthing and get your API key.

Get your endpoint domain

Upload an image in the dashboard, then find the image, click the More button, Copy File URL in the format: https://******.ufs.sh/f/******, replace ******.ufs.sh with the value of NEXT_PUBLIC_UPLOADTHING_URL in the next step

Update the environment variables

Set the environment variables in your .env file:

.env
NEXT_PUBLIC_UPLOADTHING_URL=your_uploadthing_url_without_protocol
UPLOADTHING_TOKEN=your_uploadthing_token
If you know a bit about aws s3 then you have lower cost options, S3 or Cloudflare R2 is a good option.

Cloudflare R2 Configuration [optional]

Set up Cloudflare R2 for fast, cost-effective file uploads

Why Choose Cloudflare R2?

  • 🚀 Global Performance: Cloudflare's edge network for fast uploads worldwide
  • 💰 Cost Effective: 10x cheaper than S3 with zero egress fees
  • 🔗 S3 Compatible: Works with existing S3 tools and libraries
  • 🌍 Built-in CDN: Automatic content distribution via Cloudflare's network

1. Create an R2 Bucket

  1. Go to Cloudflare Dashboard
  2. Click "R2 Object Storage" in the sidebar
  3. Click "Create bucket"
  4. Choose a unique bucket name (e.g., my-app-uploads)
  5. Select your preferred location (Auto for global performance)
  6. Click "Create bucket"

2. Configure Public Access (Optional)

  1. Go to your bucket settings
  2. Click "Settings" tab
  3. Under "Public access", click "Allow Access"

3. Custom Domain Setup

Add a CNAME record in your Custom domains like: upload.yourdomain.com

4. Generate API Token

  1. Go to "Manage R2 API tokens"
  2. Click "Create API token"
  3. Set permissions:
    • Object:Read
    • Object:Write
    • Bucket:Read
  4. Choose "Specify bucket" and select your bucket
  5. Click "Create API token"
  6. Save your Access Key ID and Secret Access Key

5. Configure CORS (If Using Custom Domain)

Comprehensive CORS Guide: For detailed CORS configuration, testing, and troubleshooting, see the CORS & ACL Configuration Guide.

In your R2 bucket settings, add this CORS policy:

[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
    "AllowedOrigins": ["http://localhost:3000", "https://yourdomain.com"],
    "ExposeHeaders": ["ETag", "Content-Length"]
  }
]

6. Set Environment Variables

Add to your .env:

.env
# Cloudflare R2 Configuration
NEXT_PUBLIC_ENABLE_UPLOADTHING=false
CLOUDFLARE_ACCOUNT_ID=your-cloudflare-account-id
R2_ACCESS_KEY_ID=your-r2-access-key-id
R2_SECRET_ACCESS_KEY=your-r2-secret-access-key
R2_BUCKET=your-r2-bucket-name
 
# Optional: Custom domain for public files
CLOUDFLARE_R2_PUBLIC_URL=https://uploads.yourdomain.com

🔒 Security Best Practices

  • Use scoped API tokens - Only grant permissions to specific buckets
  • Enable custom domain - Better security than r2.dev subdomain
  • Set up WAF rules - Protect against abuse via Cloudflare dashboard
  • Monitor usage - Set up billing alerts for unexpected usage

🆘 Common Issues

  • CORS errors? → Check your domain is in AllowedOrigins and verify custom domain setup. For detailed CORS configuration, see the CORS & ACL Configuration Guide.
  • Access denied? → Verify API token has Object:Read and Object:Write permissions
  • Slow uploads? → Ensure you're using the correct endpoint URL with your account ID
  • Custom domain not working? → Verify CNAME record and bucket public access settings

💰 Cost Comparison

ProviderStorageEgressRequests
Cloudflare R2$0.015/GBFREE 🎉$0.36/million
AWS S3$0.023/GB$0.09/GB$0.40/million
Savings35% less100% less10% less

AWS S3 Configuration [optional]

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

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 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

Comprehensive CORS Guide: For detailed CORS configuration, testing, and troubleshooting, see the CORS & ACL Configuration Guide.

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",
      "https://yourdomain.com"
    ],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }
]
  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 .env file.

DevelopmentProduction

.env
# .env
NEXT_PUBLIC_ENABLE_UPLOADTHING=false
AWS_ACCESS_KEY_ID=your_access_key_id
AWS_SECRET_ACCESS_KEY=your_secret_access_key
AWS_REGION=your_region
AWS_S3_BUCKET=your-app-uploads-prod

💰 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)

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