Documentation
supastarter for Next.jssupastarter for Next.jsStorage

AWS S3

Learn how to use AWS S3 as your storage provider with supastarter.

Amazon S3 (Simple Storage Service) is the most widely used object storage service and the original implementation of the S3 API that other providers are compatible with. It offers high durability, scalability, and integration with the broader AWS ecosystem.

1. Create an S3 bucket

Log in to the AWS Console and create a new S3 bucket.

  • Bucket name: Choose a globally unique name (e.g., your-app-avatars)
  • AWS Region: Select the region closest to your deployment target
  • Block Public Access: Keep all public access blocked (supastarter uses presigned URLs for secure access)
  • Bucket Versioning: Optional, but useful for production

Keep "Block all public access" enabled. supastarter uses presigned URLs for both uploads and downloads, so public access to the bucket is not needed.

2. Create an IAM user with S3 permissions

In the IAM Console, create a new IAM user for your application:

  1. Go to UsersCreate user
  2. Name the user (e.g., supastarter-s3)
  3. Attach the following inline policy or use the managed AmazonS3FullAccess policy (or scope it to your specific bucket):
IAM Policy (scoped to your bucket)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::your-app-avatars",
        "arn:aws:s3:::your-app-avatars/*"
      ]
    }
  ]
}
  1. Create an Access Key for the user under Security credentialsAccess keys. Copy the Access Key ID and Secret Access Key.

3. Configure CORS

In the S3 console, navigate to your bucket → PermissionsCross-origin resource sharing (CORS) and add the following configuration:

[
  {
    "AllowedHeaders": ["*"],
    "AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
    "AllowedOrigins": ["https://your-domain.com"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3600
  }
]

Replace https://your-domain.com with your actual domain. For development, add http://localhost:3000 as an additional origin.

4. Configure environment variables

Add the following to your .env.local file:

.env.local
S3_ACCESS_KEY_ID="your-aws-access-key-id"
S3_SECRET_ACCESS_KEY="your-aws-secret-access-key"
S3_ENDPOINT="https://s3.us-east-1.amazonaws.com"
S3_REGION="us-east-1"

Replace the region with your bucket's region. The endpoint follows the pattern https://s3.<region>.amazonaws.com.

5. Test the upload

Start your development server and test a file upload:

pnpm dev

Using CloudFront CDN (optional)

For production, consider placing a CloudFront distribution in front of your S3 bucket to serve files with lower latency globally. Create a CloudFront distribution with your S3 bucket as the origin and use Origin Access Control (OAC) to restrict direct access to the bucket.

Frequently asked questions

How much does AWS S3 cost?

S3 Standard storage costs approximately $0.023/GB per month. PUT requests cost $0.005 per 1,000 requests and GET requests cost $0.0004 per 1,000 requests. Data transfer out is $0.09/GB after the first 100 GB/month. For smaller workloads, the free tier includes 5 GB of storage for 12 months.

Should I use S3 or Cloudflare R2?

If you already use AWS services, S3 integrates seamlessly. If egress costs are a concern (serving many/large files), consider Cloudflare R2 which has zero egress fees. See the Cloudflare R2 guide for details.

Do I need to enable public access?

No. supastarter uses presigned URLs for all file operations, so the bucket can remain private. Files are accessed through time-limited, signed URLs that are generated by your API.

How do I limit file types or sizes?

You can configure allowed file types and maximum file sizes in packages/storage/config.ts. These limits are enforced at the API level when generating presigned URLs.