Each pattern gives the Studio set-up and the app code.

Avatars

Studio: Storage → New bucket avatars. Public bucket on. Who may upload new objects, replace, delete: custom rule $object.segments.0 equals $auth.user_id. Accepted types image/*, Largest file 2. Image transformations on with webp, largest width 512. App:

Private documents

Studio: bucket documents, Public bucket off. Who may read/upload/replace/delete: the same owner-folder rule. Signed downloads on if you hand out links. Accepted types application/pdf, Largest file 25. App: upload to <user id>/<uuid>.pdf; open with download() inside the app, or createSignedUrl() for a link. Studio: bucket photos, public, owner-folder upload rule, images only, image transformations on. App: record each photo in a photos table (key, caption, owner_id), list with from("photos").order("created_at", "desc"), and render thumbnails with ?width=320&format=auto. Load the full image only on click.

Exports generated by your server

Studio: bucket exports, private. Who may read: Signed-in users with a table rule limiting which export is theirs, or owner-folder. Who may upload new objects / replace / delete: Secret keys & Studio. App: a flow or server writes the file to <user id>/report-2026-10.csv and updates an exports record to ready. The app listens (Live records) and downloads with createSignedUrl.

Team files

Studio: bucket team-files, private, rules compare $object.segments.0 with $auth.org. App: keys acme/design/logo.png. After switchOrg("acme"), list with list({ prefix: "acme/design/" }).

Big video uploads

Studio: bucket videos, Signed uploads on, Largest file 500. App: your server issues a signed upload link per upload (Upload); the browser sends the file straight to storage and then tells your server, which creates the record.

Contract sent to a client

Studio: open the file, Sharing, 7 days, View only, copy the link (Share links). Revoke when the deal closes.

User-generated downloads with a guard

A “Download invoice” button for a private bucket:

Anti-patterns

  • Using the person’s file name as the key (collisions, path tricks).
  • Public bucket for sensitive data “because it’s easier”.
  • Storing signed URLs in the database.
  • Uploading through your own server when a signed upload would do.
  • Forgetting to clean up files for deleted records.

Bucket settings

Every option.

Troubleshooting

When something fails.