General
Storage

Setup

Learn how to set up S3-compatible storage for your application.

The starter kit supports any S3-compatible storage provider. This guide covers setting up storage with Cloudflare R2, AWS S3 and other providers.

Cloudflare R2 Setup

1. Create an R2 Bucket

  1. Go to your Cloudflare Dashboard
  2. Navigate to R2 > Create bucket
  3. Enter a bucket name (e.g., my-app-images)
  4. Choose a location
  5. Click Create bucket

2. Create API Tokens

  1. Go to Manage R2 API Tokens
  2. Click Create API Token
  3. Set permissions:
    • Object Read & Write (for uploads and downloads)
    • Bucket Read (optional, for listing)
  4. Copy the Access Key ID and Secret Access Key

3. Configure Environment Variables

Add the R2 credentials to your .env file:

.env
S3_ACCESS_KEY_ID=your-r2-access-key-id
S3_SECRET_ACCESS_KEY=your-r2-secret-access-key
S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
S3_REGION=auto
NEXT_PUBLIC_IMAGES_BUCKET_NAME=my-app-images

4. Configure CORS (Optional)

If you need to upload files directly from the browser, configure CORS:

  1. Go to your bucket settings
  2. Navigate to Settings > CORS Policy
  3. Add the following policy:
CORS Policy
[
  {
    "AllowedOrigins": ["https://yourdomain.com", "http://localhost:3000"],
    "AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }
]

AWS S3 Setup

1. Create an S3 Bucket

  1. Go to AWS S3 Console
  2. Click Create bucket
  3. Enter a bucket name
  4. Choose a region
  5. Disable public access (we'll use signed URLs)
  6. Click Create bucket

2. Create IAM User

  1. Go to IAM Console
  2. Navigate to Users > Create user
  3. Enable Programmatic access
  4. Attach the AmazonS3FullAccess policy (or create a custom policy with limited permissions)
  5. Copy the Access Key ID and Secret Access Key

3. Configure Environment Variables

.env
S3_ACCESS_KEY_ID=your-aws-access-key-id
S3_SECRET_ACCESS_KEY=your-aws-secret-access-key
S3_ENDPOINT=https://s3.amazonaws.com
S3_REGION=us-east-1
NEXT_PUBLIC_IMAGES_BUCKET_NAME=my-app-images

4. Configure CORS

  1. Go to your S3 bucket
  2. Navigate to Permissions > CORS
  3. Add the following configuration:
CORS Configuration
[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT", "POST", "DELETE"],
    "AllowedOrigins": ["https://yourdomain.com", "http://localhost:3000"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }
]

DigitalOcean Spaces Setup

1. Create a Space

  1. Go to DigitalOcean Spaces
  2. Click Create a Space
  3. Choose a name and region
  4. Disable public file listing
  5. Click Create a Space

2. Generate Access Keys

  1. Go to API > Spaces Keys
  2. Click Generate New Key
  3. Copy the Access Key and Secret Key

3. Configure Environment Variables

.env
S3_ACCESS_KEY_ID=your-spaces-access-key
S3_SECRET_ACCESS_KEY=your-spaces-secret-key
S3_ENDPOINT=https://<region>.digitaloceanspaces.com
S3_REGION=nyc3
NEXT_PUBLIC_IMAGES_BUCKET_NAME=my-app-images

MinIO Setup (Local Development)

1. Run MinIO with Docker

docker-compose.yml
services:
  minio:
    image: minio/minio
    container_name: minio
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    ports:
      - '9000:9000'
      - '9001:9001'
    volumes:
      - minio_data:/data
    command: server /data --console-address ":9001"
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://localhost:9000/minio/health/live']
      interval: 30s
      timeout: 20s
      retries: 3

volumes:
  minio_data:

2. Create a Bucket

  1. Access MinIO Console at http://localhost:9001
  2. Login with minioadmin / minioadmin
  3. Click Create Bucket
  4. Name it (e.g., my-app-images)

3. Configure Environment Variables

.env
S3_ACCESS_KEY_ID=minioadmin
S3_SECRET_ACCESS_KEY=minioadmin
S3_ENDPOINT=http://localhost:9000
S3_REGION=us-east-1
NEXT_PUBLIC_IMAGES_BUCKET_NAME=my-app-images

Storage Configuration

The storage service is configured in lib/storage/service.ts and automatically uses the environment variables you've set.

Testing the Setup

You can test your storage setup by checking if the service initializes correctly:

test-storage.ts
import { storageService } from '@/lib/storage';

// This will throw an error if credentials are missing or invalid
const testUrl = await storageService.getSignedUploadUrl(
  'test/file.txt',
  process.env.NEXT_PUBLIC_IMAGES_BUCKET_NAME!
);

console.log('Storage setup successful!');