File uploads

File uploads and storage

Let people upload photos, documents and videos. Storage is built into VibeDream, so there's no bucket or extra account to set up.

1

Ask the AI (easiest)

Tell the AI what you need, for example:

  • “Let customers upload a photo of their pet when they book.”
  • “Add a gallery where I can upload images and show them in a grid.”

The AI will:

  • switch on storage for your project and add its keys for you,
  • add an upload route to your FastAPI backend,
  • build the upload button or drop zone in your React app, with progress and error messages.

Storage needs a paid plan

Uploads count toward the storage that comes with your plan. See the FAQ below for how much you get.
2

Or wire it up yourself

If you like editing code, here's the pattern the AI uses. Once storage is on, these two values are in your backend environment. Keep them on the server and never send the token to the browser.

backend/.env
STORAGE_API_URL=<filled in by VibeDream>
STORAGE_API_TOKEN=<filled in by VibeDream>

Your backend asks VibeDream for a short-lived upload link:

FastAPI
# backend/main.py
import os
import httpx
from pydantic import BaseModel

class UploadRequest(BaseModel):
    filename: str
    mime_type: str

@app.post("/api/upload-url")
async def get_upload_url(body: UploadRequest):
    async with httpx.AsyncClient() as client:
        res = await client.post(
            f"{os.getenv('STORAGE_API_URL')}/presigned-upload",
            json={"filename": body.filename, "mimeType": body.mime_type},
            headers={"X-Storage-Token": os.getenv("STORAGE_API_TOKEN", "")},
        )
    res.raise_for_status()
    return res.json()

The browser uploads the file straight to that link:

React
// frontend/src/lib/upload.ts
export const uploadFile = async (file: File) => {
  const res = await fetch("/api/upload-url", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ filename: file.name, mime_type: file.type }),
  });
  const { uploadUrl, key } = await res.json();
  await fetch(uploadUrl, { method: "PUT", headers: { "Content-Type": file.type }, body: file });
  return key;
};
3

Storage API reference

All calls go to STORAGE_API_URL with the header X-Storage-Token.

POST/presigned-uploadGet a short-lived link the browser uploads to
POST/uploadUpload a file from your backend (multipart form)
GET/filesList files
GET/files/:key/downloadGet a short-lived download link
DELETE/files/:keyDelete a file

Common questions

How much storage do I get?

Storage comes with your plan: 25GB on All Access Mini, Unlimited on All Access.

Do I need an AWS, Firebase or Cloudinary account?

No. Storage is built into VibeDream. The AI sets it up for your project the first time you ask for uploads.

Are my users' files private?

Each project gets its own storage space. Uploads use short-lived signed links, and your storage key stays on the server, never in the browser.