Supabase Storage buckets: public vs private is a security decision, not a default
TL;DR
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.
Use this when you run into the situation in the title.
When not to use this skill: unrelated tasks. It covers only the procedure above.
Steps
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.
Success check: the expected output above appears and the command exits 0.
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.
Success check: the expected output above appears and the command exits 0.
- 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.
Name buckets per domain (avatars, invoices, product-images), not per user. Per-user buckets do not scale and complicate policies.
Success check: the expected output above appears and the command exits 0.
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.
Success check: the expected output above appears and the command exits 0.
Compatibility
Tool: Supabase. The steps above apply to the commands named in them. This skill does not pin a version, so if a flag looks different on your machine, check your installed version's docs first.
Details
Supabase Storage buckets: choose public or private deliberately
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.