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:
- Go to Users → Create user
- Name the user (e.g.,
supastarter-s3) - Attach the following inline policy or use the managed
AmazonS3FullAccesspolicy (or scope it to your specific 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/*"
]
}
]
}- Create an Access Key for the user under Security credentials → Access keys. Copy the Access Key ID and Secret Access Key.
3. Configure CORS
In the S3 console, navigate to your bucket → Permissions → Cross-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:
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 devUsing 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.