# Storage Buckets and Policies — Supabase

Source: https://www.skillbyai.com/en/supabase/s-storage

> Public files, private files and signed URLs.

## Buckets backed by Postgres metadata

Files live in **buckets**. A **public** bucket serves files to anyone through a permanent URL; a **private** bucket requires authorisation, either a user JWT or a time-limited **signed URL**. Object metadata is stored in the `storage.objects` table, so access is controlled with ordinary **RLS policies** on that table. A common convention is to put each user's files under a folder named after their user id and check it with `storage.foldername(name)`.

## Files and live updates

Storage keeps files in buckets guarded by policies; Realtime pushes changes and messages to connected clients.

![Three ideas: buckets and access, realtime channels, choosing the right tool.](assets/figures/supabase/section-5-map.svg) — Figure 5.1 — Upload, bucket policy, subscribers receiving events.

## Upload, signed URL and a folder policy

supabase-js plus SQL.

```typescript
// upload into the user's own folder of a private bucket
const path = `${user.id}/avatar.png`
await supabase.storage.from('avatars').upload(path, file, { upsert: true })

// a link that expires after 60 seconds
const { data } = await supabase.storage.from('avatars').createSignedUrl(path, 60)

// public buckets instead use a permanent URL:
// supabase.storage.from('public-assets').getPublicUrl('logo.png')

/* SQL policy on storage.objects:
create policy "users upload to own folder" on storage.objects
  for insert to authenticated
  with check (
    bucket_id = 'avatars'
    and (storage.foldername(name))[1] = (select auth.uid())::text
  );
*/
```

## Default to private buckets

Make a bucket public only for truly public assets such as logos. Everything user-related should be private with policies or signed URLs.

**Quiz:** How do you share a file from a private bucket for a short time?

- [ ] Make the bucket public temporarily
- [x] Create a signed URL with an expiry
- [ ] Send the service_role key to the user
- [ ] Disable RLS on storage.objects

*Answer:* Create a signed URL with an expiry. Signed URLs grant time-limited access.
