Skip to main content
Storage is where your app keeps uploaded files and generated media. If you skip storage, the basic app can still run, but upload-heavy features will not work properly.

Why You Need Storage

This repo uses storage for things like:
  • chat document uploads
  • generated images
  • generated videos
  • generated audio
  • user-uploaded files for vision or other tools

What You Need To Configure

STORAGE_REGION=...
STORAGE_ACCESS_KEY=...
STORAGE_SECRET_KEY=...
STORAGE_ENDPOINT=...
STORAGE_BUCKET=...
STORAGE_PUBLIC_URL=...

What These Env Vars Mean

  • STORAGE_REGION: region value expected by your provider
  • STORAGE_ACCESS_KEY: access key for your bucket
  • STORAGE_SECRET_KEY: secret key for your bucket
  • STORAGE_ENDPOINT: S3-compatible API endpoint
  • STORAGE_BUCKET: bucket name
  • STORAGE_PUBLIC_URL: the public URL users will open in the browser

The Most Important Rule

STORAGE_PUBLIC_URL must point to the same bucket your app is uploading into. If your app writes to Bucket A but your public URL points to Bucket B or the wrong CDN domain, uploads may succeed but the generated links will be broken. Cloudflare R2 is the easiest default because it is S3-compatible and simple to wire up for this kind of app.

Cloudflare R2 Setup

  1. Create a bucket in R2
  2. Generate an API token with read/write access
  3. Copy the S3 endpoint
  4. Configure a public URL using a custom domain or r2.dev
  5. Put those values into .env.local
Example:
STORAGE_REGION=auto
STORAGE_ACCESS_KEY=...
STORAGE_SECRET_KEY=...
STORAGE_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com
STORAGE_BUCKET=anotherwrapper
STORAGE_PUBLIC_URL=https://cdn.yourdomain.com

How The Repo Uses Storage

The main files are:
  • lib/storage/object-storage.ts
  • lib/clients/cloudflare.ts
That is where uploads, deletes, and public URLs are handled.

Verification Checklist

Your storage setup is working if:
  • you can upload a file
  • generated media saves successfully
  • the stored file URL opens in the browser

Common Mistakes

  • wrong bucket name
  • wrong endpoint
  • STORAGE_PUBLIC_URL pointing at the wrong bucket or domain
  • creating the env vars but not restarting the app