A free, open-source, client-side AWS S3 file manager. Browse, upload, download, and manage your S3 buckets directly in your browser — no server, no backend, no sign-up required.
Live: http://localhost:3000 (run locally)
This is one of the most important things to understand about this app.
When you enter your AWS Access Key ID and Secret Access Key in Settings, they are saved only to your browser's localStorage — a sandboxed storage area that is:
- Scoped to
localhost:3000(or your domain) — no other website can read it - Never included in any network request made by this app to any server other than AWS directly
- Not sent to the app's developers, any analytics service, or any third party
You can verify this yourself: open DevTools → Network tab, enter your credentials, and observe — the only requests leaving your browser go directly to *.amazonaws.com.
This app has no backend server. Every S3 operation (listing files, uploading, downloading, deleting) is a direct HTTPS request from your browser to the AWS S3 API. The request path is:
Your Browser → AWS S3 API (*.amazonaws.com)
There is no intermediate server, proxy, or relay. AWS validates your credentials on their end using standard AWS Signature Version 4 signing — the same mechanism used by the official AWS CLI and SDKs.
File downloads and image previews do not stream file content through the app. Instead, the app asks AWS to generate a presigned URL — a time-limited, cryptographically signed URL that grants temporary direct access to a specific object. This means:
- File bytes go directly from S3 to your browser
- Presigned URLs expire after 15 minutes
- No file content is ever processed or cached by this app
| Risk | Mitigation |
|---|---|
| Shared or public computers | Always click Settings → Clear before leaving |
| Overly permissive IAM credentials | Use the minimum IAM policy listed in this README |
| Browser extensions | Malicious extensions can read localStorage — use a clean browser profile |
| Leaked credentials | Rotate your access keys regularly; revoke immediately if compromised |
Your AWS credentials are stored exclusively in your browser's
localStorage. They are never transmitted to any server, third-party service, or external endpoint outside of AWS.
- Intended for personal or development use on trusted devices only.
- Do not use on shared or public computers.
- Never use root account credentials — always use a scoped IAM user.
- Treat credentials like passwords — rotate regularly and revoke if compromised.
- Multi-bucket explorer — access all configured S3 buckets from one interface
- Drag & drop upload — with real-time per-file progress bars
- Download via presigned URLs — time-limited, secure download links (15 min expiry)
- Image preview — preview images directly in the browser
- Folder navigation — browse S3 prefixes as folders with breadcrumb trail
- Create folders — create new S3 prefix paths
- Bulk delete — multi-select and delete multiple files at once
- Copy presigned URL — copy shareable links to clipboard
- Search & sort — filter files by name, sort by name/size/date
- List & grid view — toggle between table and card layouts
- Versioned bucket support — correctly deletes all versions and delete markers
- S3-compatible endpoints — works with MinIO, Cloudflare R2, and other S3-compatible services
npm install
npm run devOpen http://localhost:3000, go to Settings, and enter your AWS credentials.
All API calls are made using the official AWS SDK for JavaScript v3 (@aws-sdk/client-s3). Below is every AWS API operation this app calls, what it is used for, and whether it requires CORS to be configured on the bucket.
| AWS API Operation | SDK Command | Used For | CORS Required |
|---|---|---|---|
HeadBucket |
HeadBucketCommand |
Test connection to verify credentials and bucket access | Yes |
GetBucketVersioning |
GetBucketVersioningCommand |
Detect if versioning is enabled before deleting objects | Yes |
ListObjectsV2 |
ListObjectsV2Command |
List files and folders inside a bucket at a given prefix | Yes |
ListObjectVersions |
ListObjectVersionsCommand |
List all versions and delete markers for an object (versioned buckets) | Yes |
PutObject |
PutObjectCommand |
Upload files and create folder placeholders | Yes |
DeleteObjects |
DeleteObjectsCommand |
Delete one or more objects (or specific versions) | Yes |
GetObject |
GetObjectCommand |
Generate presigned download URLs (file is fetched directly by the browser) | Yes |
The ListBuckets API (s3.amazonaws.com/?x-id=ListBuckets) is a global service-level endpoint that AWS has never added CORS support to. Any call to it from a browser is blocked with a CORS preflight error — regardless of what CORS policy your bucket has. This is an AWS limitation, not a bug in this app.
For this reason, bucket names are entered manually in the Settings page instead of being auto-discovered.
All AWS SDK requests are signed using AWS Signature Version 4 (SigV4). Your credentials are used locally by the SDK to compute an HMAC-SHA256 signature that is attached to each request as an Authorization header. The raw secret key itself is never sent over the network — only the derived signature is.
Presigned URLs are generated client-side using @aws-sdk/s3-request-presigner. They are signed URL strings that encode temporary, scoped permission to access one specific S3 object. The signing uses your credentials locally — no network request is made to generate them.
Create a dedicated IAM user with the following policy. Replace YOUR_BUCKET_NAME with your actual bucket name. Repeat the statements for each additional bucket.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "BucketLevel",
"Effect": "Allow",
"Action": [
"s3:ListBucket",
"s3:GetBucketLocation",
"s3:GetBucketVersioning",
"s3:ListBucketVersions"
],
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME"
},
{
"Sid": "ObjectLevel",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:DeleteObjectVersion"
],
"Resource": "arn:aws:s3:::YOUR_BUCKET_NAME/*"
}
]
}| Permission | Why it's needed |
|---|---|
s3:ListBucket |
List files and folders inside a bucket |
s3:GetBucketLocation |
Determine the bucket's region |
s3:GetBucketVersioning |
Detect if versioning is enabled (affects delete behavior) |
s3:ListBucketVersions |
List all object versions for permanent deletion |
s3:GetObject |
Download files and generate presigned URLs |
s3:PutObject |
Upload files and create folders |
s3:DeleteObject |
Delete files (non-versioned buckets) |
s3:DeleteObjectVersion |
Permanently delete specific versions (versioned buckets) |
Every bucket you access must have a CORS policy applied. Without it, the browser blocks all requests.
AWS Console → S3 → [your bucket] → Permissions → Cross-origin resource sharing (CORS) → Edit:
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "PUT", "POST", "DELETE", "HEAD"],
"AllowedOrigins": ["http://localhost:3000"],
"ExposeHeaders": ["ETag"],
"MaxAgeSeconds": 3000
}
]For production, replace http://localhost:3000 with your deployed domain.
Apply via AWS CLI:
aws s3api put-bucket-cors \
--bucket YOUR_BUCKET_NAME \
--cors-configuration file://cors.json- AWS Console → IAM → Users → Create user
- Select Attach policies directly → Create policy → paste the JSON above
- After creating the user: Security credentials → Create access key
- Choose Local code as the use case
- Copy the Access Key ID and Secret Access Key (shown only once — save them securely)
- Open the app → Settings → enter your credentials and bucket name(s) → Save
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router) |
| Language | TypeScript |
| Styling | Tailwind CSS v4 |
| AWS SDK | @aws-sdk/client-s3 v3, @aws-sdk/s3-request-presigner |
| State | Zustand v5 |
| Icons | Lucide React |
| Persistence | Browser localStorage only — no database, no backend |
app/
page.tsx # Landing page (SSG)
app/page.tsx # File explorer (client)
settings/page.tsx # Credentials + bucket config
robots.ts # robots.txt
sitemap.ts # sitemap.xml
components/
landing/ # Hero, Features, HowItWorks, Footer
layout/ # AppHeader, Sidebar, Breadcrumb
s3/ # FileList, FileRow, FileGridCard, UploadZone, modals
ui/ # Button, Input, Modal, Toast, Badge, Spinner
seo/ # JsonLd
lib/
s3.ts # AWS SDK operations
store.ts # Zustand store
credentials.ts # localStorage helpers
utils.ts # Formatting + utility functions
hooks/
useS3.ts # File fetching hooks
useToast.ts # Toast notification helpers
S3 File Manager is an independent open-source project and is not affiliated with, endorsed by, or sponsored by Amazon Web Services (AWS). AWS and Amazon S3 are trademarks of Amazon.com, Inc. Use of this tool is at your own risk. The authors accept no liability for data loss, unauthorized access, or any other damages arising from its use.