84  84. Step 10: Set Up Supabase Storage Bucket

As of Oct 22, 2026 · Official docs: Supabase Storage

You’ll store task images in Supabase Storage, in a bucket: a named container for files, like a top-level folder in a cloud drive.

84.1 The Migration Already Created the Bucket

You don’t create the bucket by hand, so skip any manual bucket steps you may find in older instructions. The migration supabase/migrations/3_init_storage_schema.sql, which ran when Claude ran npx supabase db push for you in Step 9 ((G) Create the database in Classes 10–12), already created it, with its settings and policies. The bucket is named task-attachments, the name the app’s code uses.

Don’t create a task-images bucket

Earlier versions of this page told you to create a bucket named task-images. The app never uses a bucket with that name. If you created one, you can delete it.

84.2 What the Migration Set Up

Bucket settings:

  • Public: anyone who has an image’s URL can view it (simpler for tutorials). For production, consider a private bucket with signed URLs, links that work only for a limited time.
  • File size limit: 1 MB. Supabase refuses larger files, whatever the upload page does. (An upload page can also check the size first, to give a friendly message before the file is sent.)
  • Allowed file types: images only:
    • image/jpeg
    • image/png
    • image/gif
    • image/webp

Storage policies (rules that Supabase checks on every request):

  • Anyone can view the files.
  • Signed-in users can upload files, but only into a folder named after their own user ID. The app saves each image under a path that starts with the uploader’s ID.
  • Signed-in users can delete files only in their own folder.

The migration also deletes a task’s image from storage when the task is deleted.

84.3 Check It in the Dashboard

  1. In the Supabase dashboard, open Storage. You should see the task-attachments bucket, marked as public.
  2. Open the bucket’s settings (its Edit option) to see the size limit and the allowed file types.
  3. Open the storage Policies page to see the three policies.

If the bucket is missing, npx supabase db push didn’t finish. Run it again and read its output for errors.

Practice Questions

Easy

Question 1 · Short answer

What is a Supabase Storage bucket, and what does this app keep in it?

A bucket is a named container for files in Supabase Storage - think of it as a top-level folder in a cloud drive. This app keeps the images that users attach to their tasks in it.

Question 2 · Multiple choice

The migration makes the bucket Public. What does that setting mean?

  1. Anyone on the internet can upload files to the bucket
  2. Anyone who has a file’s URL can view that file
  3. Anyone can delete files from the bucket
  4. Only the user who uploaded a file can view it

b. “Public” is about viewing: anyone who has a file’s URL can open it without signing in. Uploading (a) and deleting (c) are still controlled by the bucket’s policies - here, only signed-in users can upload, and users can delete only their own images. Option d describes a private setup, which the page suggests considering for production.

Question 3 · Multiple choice

The bucket allows only the file types image/jpeg, image/png, image/gif and image/webp. Which of these files would be rejected? (Assume every file is under the size limit.)

  1. team-photo.jpg
  2. logo.png
  3. budget-report.pdf
  4. celebration.gif

c. A PDF is not an image, so it is not on the allowed list. JPEG (a), PNG (b) and GIF (d) images are all allowed. Labels such as image/png are called MIME types: a standard way of naming what kind of data a file contains.

Question 4 · True or false

You have to create the storage bucket and its policies by hand in the Supabase dashboard before the app can store images.

False. The project’s migration 3_init_storage_schema.sql (one of the SQL files in supabase/migrations/) creates the bucket, its settings and its policies when you run npx supabase db push. In the dashboard you only check that they are there.

Medium

Question 5 · Matching

Match each setting or policy with what it does.

Setting or policy What it does
1. Public bucket A. Only signed-in users can add files
2. Private bucket + signed URLs B. A user can remove only their own images
3. Upload policy C. Anyone who has a file’s URL can view it
4. Delete policy D. Files can be viewed only through special links that the app hands out

1 → C, 2 → D, 3 → A, 4 → B.

A signed URL is a link to one private file that works only for a limited time. That is why a private bucket gives you more control.

Question 6 · Short answer

Earlier versions of this page told students to create a bucket named task-images by hand, but the app’s code uses a bucket named task-attachments. Why must the bucket’s name match the name used in the code, and what happens if it doesn’t?

The app finds the bucket by its name: the code says, in effect, “upload this file to the bucket called X” and “show the image stored in bucket X”. If your bucket’s name is different (even by one character), the app is asking for a bucket that doesn’t exist, so uploads fail (typically with a “Bucket not found” error) and images don’t appear. A student who created only task-images would have an empty bucket the app never uses. To find the name the code expects, search the project’s code and its migration files (supabase/migrations/) for the bucket name.

Question 7 · Scenario

Maria tries to attach a 3 MB photo of a whiteboard (a PNG file) to one of her tasks. The bucket’s size limit is 1 MB. What should happen? Is this a bug?

The upload should be rejected, ideally with a clear error message, and the photo should not be saved. That is not a bug - it’s the size limit doing its job. Maria can shrink or compress the photo to under 1 MB and try again. (The next step, “Run the Application”, asks you to test exactly this.)

Question 8 · Scenario

When a signed-in user tries to upload an image from the app, the upload fails with an error like “new row violates row-level security policy”. Based on this page, what is most likely missing, and how could you fix it?

The upload policy - the rule that allows signed-in users to add files to the bucket, in their own folder - is missing, or the upload doesn’t match it. Supabase checks the bucket’s policies on every upload and refuses anything they don’t allow. Check the storage Policies page in the dashboard. If the policies are missing, the migration didn’t run completely: run npx supabase db push again and read its output. It is also worth confirming that the user really is signed in.

Hard

Question 9 · Long answer

A file-size limit can be enforced in the upload page (the UI) and on the server (here, the bucket’s own 1 MB limit in Supabase). Explain what each of these two places adds, and why a check only in the upload page is not enough.

  • A check in the UI (the upload page in the browser) gives instant, friendly feedback (“File must be under 1 MB”) before the file is even sent.
  • A server-side check (for example, the bucket’s own size limit in Supabase) is enforced no matter how the request arrives.

A UI-only check is not enough because the browser is under the user’s control: someone can skip your web page and send files straight to Supabase (for example, with a short script), or tamper with the page’s code. Only a check on the server can’t be bypassed. Best practice is both: the UI for convenience, the server for protection.

Question 10 · Scenario

Suppose the app saves each image under a path that starts with the uploader’s user ID, for example maria-user-id/whiteboard.png (in real life the ID is a long random string). Explain how a delete policy can use that path so that Sam cannot delete Maria’s image.

When someone asks to delete a file, the policy compares the first folder in the file’s path with the user ID of the person making the request (Supabase knows who is signed in). Maria’s image is stored under her ID, so when Sam - signed in with a different ID - tries to delete it, the two don’t match and Supabase refuses. When Maria deletes it, they match and the delete is allowed. This is how the migration’s delete policy works.

Question 11 · Compare

The page calls a public bucket “simpler for tutorials” but suggests a private bucket with signed URLs for production. Imagine the app adds a feature where employees upload photos of expense receipts. Which option would you choose, and why? Mention one downside of your choice.

A private bucket with signed URLs. Receipts can contain sensitive information (names, amounts, the last digits of a card). In a public bucket, anyone who gets hold of an image’s URL - for example from a forwarded email - can view it without signing in. With a private bucket, the app first checks who is asking and then hands out a signed URL that stops working after a short time.

Downside: more work. The app has to create a signed URL every time it shows an image, and old links stop working once they expire. For harmless images in a class project, a public bucket is fine.

© 2025-2026 Y. Rosenthal. All rights reserved.