AWS S3 connects to Storage UI with a bucket name, its region, and an IAM Access Key ID and Secret Access Key.
1. Create a bucket
- Open the S3 console and select Create bucket.
- Enter a globally unique bucket name.
- Choose an AWS Region and note its code (for example
us-east-1). Storage UI needs the exact region. - Keep Block Public Access enabled; Storage UI reaches the bucket with signed credentials, not public access.
- Create the bucket.
2. Create an access key
Storage UI authenticates as an IAM identity. Create a dedicated IAM user so its permissions can be scoped to this bucket.
- Open the IAM console and create a user (programmatic access).
- Attach a policy that grants access to the bucket only:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": "arn:aws:s3:::my-bucket"
},
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
- Create an access key for the user and save both values:
- Access Key ID
- Secret Access Key
The Secret Access Key is only shown once. Store it securely and never expose it through a NEXT_PUBLIC_* variable.
For read-only access, drop s3:PutObject and s3:DeleteObject from the policy and set STORAGE_1_READ_ONLY=true (see below).
3. Configure Storage UI
Add the connection to .env.local for local development, or to the environment variable settings on your deployment platform:
STORAGE_1_PROVIDER=s3
STORAGE_1_NAME=AWS S3
STORAGE_1_BUCKET=my-bucket
STORAGE_1_REGION=us-east-1
STORAGE_1_ACCESS_KEY_ID=your-access-key-id
STORAGE_1_SECRET_ACCESS_KEY=your-secret-access-key
Replace my-bucket and us-east-1 with your bucket's name and region. Always set the real region: without it the connection falls back to auto, which AWS does not accept.
4. Configure CORS
Storage UI uploads and previews files directly from the browser using presigned URLs, so the bucket must allow your app's origin. In the bucket's Permissions -> Cross-origin resource sharing (CORS), add:
[
{
"AllowedOrigins": ["https://storage.example.com"],
"AllowedMethods": ["GET", "PUT", "POST", "HEAD"],
"AllowedHeaders": ["*"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3000
}
]
Replace https://storage.example.com with the exact origin where Storage UI runs (for local development, http://localhost:3000). Without this, listing the bucket still works, but uploads and file previews fail with a CORS error.
5. Optional settings
Enable read-only mode when the key only has read access, or when users should not modify objects:
STORAGE_1_READ_ONLY=true
If the bucket is served through a public domain or CloudFront distribution, configure its public base URL:
STORAGE_1_PUBLIC_BASE_URL=https://files.example.com
6. Restart Storage UI
Restart the development server after changing .env.local:
bun run dev
For a hosted deployment, save the environment variables and redeploy. The AWS S3 connection will then appear in the sidebar.
Troubleshooting
The bucket does not appear
Confirm that the bucket name, region, Access Key ID, and Secret Access Key are all set under the same STORAGE_n_* number.
Access is denied
Check that the IAM policy allows s3:ListBucket on the bucket and s3:GetObject on its objects. Uploads and deletes also need s3:PutObject and s3:DeleteObject.
Uploads or previews fail with a CORS error
Add the origin where Storage UI runs to the bucket's CORS configuration (step 4). The methods must include GET and PUT.
The region is not valid
A real region is required for AWS S3. Make sure STORAGE_n_REGION matches the bucket's region exactly; auto and an empty value are rejected by AWS.