What you get
Per project: an S3-compatible bucket, accessed through MIOSA endpoints. Credentials injected as env vars:
STORAGE_BUCKET=miosa-proj_xxx-uploads
STORAGE_ENDPOINT=https://storage.miosa.app
STORAGE_KEY_ID=...
STORAGE_KEY_SECRET=... Your code uses the standard S3 client libraries:
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3"
const s3 = new S3Client({
endpoint: process.env.STORAGE_ENDPOINT,
credentials: {
accessKeyId: process.env.STORAGE_KEY_ID!,
secretAccessKey: process.env.STORAGE_KEY_SECRET!,
},
region: "us-east-1",
})
await s3.send(new PutObjectCommand({
Bucket: process.env.STORAGE_BUCKET,
Key: "uploads/foo.png",
Body: pngBuffer,
})) Signed URLs for browser uploads
Don’t proxy file uploads through your runtime. Mint a signed URL server-side; the browser uploads directly to storage:
// Server
const url = await miosa.storage.signedUrl({
bucket: process.env.STORAGE_BUCKET!,
key: `users/${userId}/avatar.png`,
operation: "put",
expiresInSec: 300,
contentType: "image/png",
})
return { uploadUrl: url } // Browser
await fetch(uploadUrl, {
method: "PUT",
body: file,
headers: { "Content-Type": "image/png" },
}) Same pattern for downloads (operation: "get"). Signed URLs are scoped (single key, single operation, short expiry) — no risk of leaking bucket-wide credentials to a browser.
Public vs private
Each object can be private (default; access only via signed URL) or public (served from a *.storage.miosa.app URL). Public objects can also be fronted by a custom domain via your project’s Domain settings.
Bandwidth and storage costs
Two billable dimensions:
- Storage — GB-month for stored bytes.
- Egress — GB out from MIOSA to the public internet. Storage-to-runtime within MIOSA is free.
Attribution is carried on every event for chargeback.
Limits
| Limit | Default | Tunable |
|---|---|---|
| Storage per project | 1 GB | Yes (plan-dependent) |
| Max object size | 5 GB | Up to 100 GB for multipart |
| List keys per call | 1000 | Standard S3 pagination |
Sandboxes can use the bucket too
The same env vars are injected into sandboxes for dev / testing. Upload from inside a sandbox:
await sandbox.exec({
cmd: "aws",
args: ["s3", "cp", "/workspace/build.tar.gz", `s3://${process.env.STORAGE_BUCKET}/builds/`],
env: {
AWS_ACCESS_KEY_ID: process.env.STORAGE_KEY_ID,
AWS_SECRET_ACCESS_KEY: process.env.STORAGE_KEY_SECRET,
AWS_ENDPOINT_URL: process.env.STORAGE_ENDPOINT,
},
}) Bring your own bucket?
Yes. Set the env vars to point at an external S3-compatible bucket (real AWS, Backblaze B2, R2, etc.). MIOSA injects whatever you set.
Python SDK
See also
- Overview — the broader data plane
- Environments — per-env bucket names