Services
Storage
A private S3-compatible bucket per project, with a file browser and presigned URLs.
Deploy
Click Deploy on the Storage card. CloudHike.dev creates a bucket named proj-<slug> and an access key that can only list, read, write and delete in that one bucket. The free plan includes 500 MB, Pro 50 GB.
| Variable | Meaning |
|---|---|
S3_ENDPOINT | The S3 address to send requests to |
S3_REGION | The region string SDKs expect |
S3_BUCKET | Your bucket name. Put every object here |
S3_ACCESS_KEY_ID | The access key |
S3_SECRET_ACCESS_KEY | The secret key. Server only |
The card has Reveal and Copy for the secret, Copy as .env, Reset keys, Delete and a ready-made AWS SDK sample.
Use the S3 SDK
Any S3 library works. Set forcePathStyle to true so the bucket name goes in the path.
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
export const s3 = new S3Client({
endpoint: process.env.S3_ENDPOINT,
region: process.env.S3_REGION,
forcePathStyle: true,
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY_ID!,
secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
},
});
const Bucket = process.env.S3_BUCKET!;
export async function upload(key: string, body: Buffer, contentType: string) {
await s3.send(new PutObjectCommand({ Bucket, Key: key, Body: body, ContentType: contentType }));
}
// A link that works for one hour, for downloads or direct browser uploads.
export const downloadUrl = (key: string) =>
getSignedUrl(s3, new GetObjectCommand({ Bucket, Key: key }), { expiresIn: 3600 });
export const uploadUrl = (key: string, contentType: string) =>
getSignedUrl(s3, new PutObjectCommand({ Bucket, Key: key, ContentType: contentType }), { expiresIn: 3600 });To let users upload from the browser, create the presigned upload URL on your server and have the browser PUT the file to it. The file never passes through your server.
const { url } = await fetch("/api/upload-url", { method: "POST", body: JSON.stringify({ name: file.name, type: file.type }) }).then((r) => r.json());
await fetch(url, { method: "PUT", headers: { "content-type": file.type }, body: file });Buckets are private. Share files with presigned links, which expire, or serve them through your own server. Do not put the access key in browser code.
Storage browser
Click Open storage on a ready Storage card to manage files from the dashboard.
- Files: folders and files with size, type and date. Sort, page 25 to 250 at a time, and search a folder and everything below it.
- Preview: images, video, audio and PDFs play inline, and text and JSON are shown (the first 256 KB). Download, Copy URL and Delete are there too.
- Upload: drop files on the list or click Upload. They go straight to the bucket three at a time with progress. Replacing a file asks first.
- New folder: creates an empty folder. Deleting a folder removes everything in it.
- Stats: object and folder counts, space used against your limit, a breakdown by type, and the largest files.
Copy URL copies a presigned link that expires after an hour.
Limits and behavior
- Uploads that would go over your plan's limit are refused up front.
- A bucket over its limit for 3 days is paused: uploads and new folders are refused, deleting still works.
- Database backups live in the bucket under
_backups/postgres/and count toward the size. - Browser uploads need a CORS rule on the bucket. New buckets get one automatically on AWS; local MinIO accepts uploads from any site.
- Reset keys creates a new access key and secret. Update your app's env file afterwards.
Use with AI
Ask an agent to add file uploads and downloads to your app with your project's bucket.
- 1
Open a terminal in your app's folder and start Claude Code.
claude
- 2
Paste the prompt below and press Enter. Approve the file edits and commands it asks about.
- 3
Optional: save a short note about CloudHike.dev in CLAUDE.md so every session knows about it.
Read https://cloudhike.dev/docs/md/storage, then add file uploads to this app using my CloudHike.dev Storage bucket. - S3_ENDPOINT, S3_REGION, S3_BUCKET, S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY are in my env file (if not, follow https://cloudhike.dev/prompt.md to download them). - Use @aws-sdk/client-s3 with forcePathStyle: true, from server code only. - Upload straight from the browser using presigned PUT URLs created on the server, and show files with presigned GET URLs. - Never expose the access keys to the browser and never make the bucket public.
Replace the placeholders in <angle brackets> before sending. Always review what the agent changes.
