# Supabase Storage buckets: choose public or private deliberately

A public bucket serves files to anyone with the URL. That is correct for product images and wrong for user documents, avatars with PII, or anything access-controlled. Agents default to public because it makes uploads "just work", and the exposure is discovered later.

## Checkable procedure

1. Create the bucket with the right visibility from the start. Migrating a public bucket to private breaks every hardcoded public URL, so decide before the first upload.
2. Set file size limits and allowed MIME types on the bucket. Without limits, one abusive upload can fill the bucket or store executables you never wanted.
3. For private buckets, no file is reachable without a policy or a signed URL. That is the point. Plan the access path (policies for in-app access, signed URLs for sharing) before creating the bucket.
4. Name buckets per domain (`avatars`, `invoices`, `product-images`), not per user. Per-user buckets do not scale and complicate policies.
5. Enable the RLS policies on `storage.objects` for every bucket you care about. Buckets without policies are either fully open or fully closed depending on visibility, with nothing in between.

## Quick test

Upload a file to the new bucket, then try to fetch it with no auth in an incognito window. Public buckets should serve it; private buckets must 403. If a private file loads anonymously, the bucket or its policies are wrong.