Stockage et temps réel
Ce que tu vas apprendre
- Envoyer une photo dans un bucket et obtenir son adresse.
- Écrire des règles d'accès sur le stockage, comme pour les tables.
- Réagir en direct aux changements d'une table avec Realtime.
Les buckets
Le stockage de Supabase range des fichiers (photos, PDF) dans des buckets, des dossiers de plus haut niveau. Un bucket est public ou privé.
| Bucket | Accès | Adresse |
|---|---|---|
| Public | Tout fichier est lisible par tous | URL fixe |
| Privé | Réservé aux personnes autorisées | URL signée, temporaire |
Crée un bucket photos-recettes dans la section Storage du tableau de bord. Pour une photo publique de plat, le bucket public suffit.
Envoyer un fichier
<script setup lang="ts">
const supabase = useSupabaseClient()
const user = useSupabaseUser()
async function envoyer(event: Event) {
const fichier = (event.target as HTMLInputElement).files?.[0]
if (!fichier || !user.value) return
const chemin = `${user.value.sub}/${fichier.name}`
const { error } = await supabase.storage
.from('photos-recettes')
.upload(chemin, fichier)
if (error) console.error(error.message)
}
</script>
Le fichier vient d'un <input type="file" @change="envoyer">. Le chemin commence par l'identifiant de l'utilisateur : chaque personne a son dossier.
Pour remplacer un fichier existant, passe l'option { upsert: true } en troisième argument.
Obtenir l'adresse d'une photo
Pour un bucket public, getPublicUrl donne l'adresse :
const { data } = supabase.storage
.from('photos-recettes')
.getPublicUrl('chemin/crepes.jpg')
console.log(data.publicUrl)
Pour un bucket privé, createSignedUrl crée un lien temporaire :
const { data } = await supabase.storage
.from('photos-recettes')
.createSignedUrl('chemin/crepes.jpg', 3600)
console.log(data?.signedUrl)
Le second argument est la durée de validité. Un lien signé ne peut pas être révoqué seul : il faut supprimer, déplacer ou renommer le fichier.
Protéger le stockage
Les fichiers sont gérés par la table storage.objects, protégée par la RLS comme tes tables. Sans politique, l'envoi est refusé.
Cette politique autorise un connecté à envoyer des fichiers uniquement dans son dossier :
create policy "Envoyer dans son dossier"
on storage.objects for insert
to authenticated
with check (
bucket_id = 'photos-recettes'
and (storage.foldername(name))[1] = (select auth.jwt()->>'sub')
);
storage.foldername(name) découpe le chemin en dossiers. Le premier doit être ton identifiant, sub dans le JWT.
Le temps réel
Avec Realtime, la base prévient ton site dès qu'une ligne change, sans rechargement. Tu l'utilises par exemple pour qu'une recette ajoutée apparaisse chez tous les visiteurs.
Il faut d'abord activer Realtime sur la table. Dans le tableau de bord, ouvre les réglages des publications et active la table dans supabase_realtime. En SQL :
alter publication supabase_realtime
add table recettes;
S'abonner aux changements
<script setup lang="ts">
const supabase = useSupabaseClient()
const canal = supabase
.channel('recettes-en-direct')
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'recettes' },
(payload) => console.log(payload)
)
.subscribe()
onUnmounted(() => supabase.removeChannel(canal))
</script>
Un canal est une connexion ouverte avec le serveur. event: '*' écoute les ajouts, modifications et suppressions. table restreint l'écoute à recettes.
removeChannel ferme le canal quand tu quittes la page. Sans lui, la connexion reste ouverte inutilement.
À retenir
- Les fichiers vivent dans des buckets, publics (URL fixe) ou privés (URL signée temporaire).
uploadenvoie,getPublicUrletcreateSignedUrldonnent l'adresse.- Le stockage a sa propre RLS, sur
storage.objects: une politique par usage, par exemple un dossier par utilisateur. - Realtime demande d'ajouter la table à la publication
supabase_realtime. channel().on('postgres_changes', ...).subscribe()écoute,removeChannelferme.- Aucune clé secrète dans ces exemples : tout passe par la clé publique et la RLS.
Pour aller plus loin
Sources officielles
Ensuite
- Projet
- Lignes de code
- Niveau
- Cave
- Appartement
- Supabase
- Pièce
- 6/7
- Plan n°
- supabase/06.stockage-et-temps-reel