Skip to content

Where uploaded files go

A file field needs somewhere to put the bytes. Flare ships four drivers and flare create asks which one you want:

Terminal window
npx flare create shop --storage cloudinary

or answer the question it asks when you leave the flag off. Whatever you pick is written into the app’s env file as STORAGE_DRIVER, with the variables it needs and a link to where they live.

Provider Needs an account Free tier Best for
Cloudflare R2 (default) Yes, with a card on file 10 GB, no egress charge Almost everything. The default for a reason
Local disk No — Developing without Docker; one server you own
Cloudinary Yes 25 GB + transformations Images that need resizing, cropping, format conversion
UploadThing Yes 2 GB Getting started fastest; no bucket to configure

One line in .env (Next.js) or .dev.vars (Cloudflare):

STORAGE_DRIVER=cloudinary

plus that provider’s variables. Nothing else in the app changes — the file field, the drop zone, the size cap, the type check and createUploadUrl are identical whichever driver is underneath. Files already uploaded stay where they are, so a switch is not a migration; it decides where the next upload goes.

With R2 and disk, a read URL is a short-lived signed token that app/api/storage/route.ts redeems, so whoever issued it decided the viewer was allowed it.

Cloudinary and UploadThing are content delivery networks. Serving through your app would throw away the thing you are paying them for, so they hand back their own URL, which anyone with the link can read and which does not expire. That is the normal way to use them, and the wrong way to store a passport scan.

STORAGE_PUBLIC=false

makes every read signed and proxied by your app instead, and they become ordinary private storage with a good pipeline attached.

Each is an ordinary file in lib/storage/ in your repository. A driver answers three questions — store these bytes, give them back, throw them away — and lib/storage.ts is the only place that knows which one is in use. See file uploads for the field itself and writing another one to add your own.