Supabase Realtime permet de recevoir des mises à jour en temps réel depuis votre base de données PostgreSQL via WebSockets. Idéal pour les chats, tableaux de bord live, applications collaboratives et notifications instantanées.
Pour les fondations, consultez notre guide complet Supabase. Pour activer les changements sur vos tables, voir créer et structurer sa base de données Supabase. Pour sécuriser les channels avec RLS, voir Supabase RLS. Pour intégrer le Realtime dans React, voir Supabase avec React. Pour intégrer dans Next.js, voir Supabase avec Next.js. Pour déclencher des actions serveur sur les changements, voir Edge Functions Supabase.
Comment Fonctionne Supabase Realtime
Supabase Realtime utilise le système de Logical Replication de PostgreSQL pour capturer les changements (INSERT, UPDATE, DELETE) et les diffuser via WebSockets. Il existe 3 fonctionnalités Realtime :
- Broadcast : envoyer des messages éphémères entre clients
- Presence : suivre les utilisateurs connectés en temps réel
- Postgres Changes : écouter les changements de la base de données
Activer Realtime sur une Table
-- Via SQL
ALTER PUBLICATION supabase_realtime ADD TABLE posts;
ALTER PUBLICATION supabase_realtime ADD TABLE messages;
-- Ou dans Dashboard > Database > Replication
Postgres Changes : Écouter les Changements DB
const channel = supabase
.channel('posts-changes')
.on(
'postgres_changes',
{
event: '*', // INSERT, UPDATE, DELETE, ou '*' pour tout
schema: 'public',
table: 'posts'
},
(payload) => {
console.log('Type:', payload.eventType) // INSERT | UPDATE | DELETE
console.log('Nouveau:', payload.new)
console.log('Ancien:', payload.old)
}
)
.subscribe()
// Arrêter l'écoute
await supabase.removeChannel(channel)
Filtrer les changements
// Écouter seulement les messages d'une conversation spécifique
const channel = supabase
.channel('conversation-123')
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'messages',
filter: `conversation_id=eq.${conversationId}`
},
(payload) => {
addMessage(payload.new)
}
)
.subscribe()
Application Chat en Temps Réel
export function ChatRoom({ roomId }: { roomId: string }) {
const [messages, setMessages] = useState<Message[]>([])
const [newMessage, setNewMessage] = useState('')
const bottomRef = useRef<HTMLDivElement>(null)
// Charger les messages initiaux
useEffect(() => {
supabase
.from('messages')
.select('*, profiles(username)')
.eq('room_id', roomId)
.order('created_at', { ascending: true })
.limit(50)
.then(({ data }) => setMessages(data ?? []))
}, [roomId])
// Écouter les nouveaux messages
useEffect(() => {
const channel = supabase
.channel(`room-${roomId}`)
.on(
'postgres_changes',
{
event: 'INSERT',
schema: 'public',
table: 'messages',
filter: `room_id=eq.${roomId}`
},
(payload) => {
setMessages(prev => [...prev, payload.new as Message])
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
}
)
.subscribe()
return () => { supabase.removeChannel(channel) }
}, [roomId])
const sendMessage = async () => {
if (!newMessage.trim()) return
await supabase.from('messages').insert({ content: newMessage, room_id: roomId })
setNewMessage('')
}
}
Presence : Savoir qui est en Ligne
const channel = supabase.channel('online-users', {
config: { presence: { key: userId } }
})
channel
.on('presence', { event: 'sync' }, () => {
const state = channel.presenceState()
console.log('Utilisateurs en ligne:', Object.keys(state).length)
})
.on('presence', { event: 'join' }, ({ key }) => {
console.log(`${key} vient de rejoindre`)
})
.on('presence', { event: 'leave' }, ({ key }) => {
console.log(`${key} vient de partir`)
})
.subscribe(async (status) => {
if (status === 'SUBSCRIBED') {
await channel.track({
user_id: userId,
username: 'jeandupont',
online_at: new Date().toISOString()
})
}
})
Broadcast : Messages Éphémères
// Indicateur "est en train d'écrire"
channel
.on('broadcast', { event: 'typing' }, ({ payload }) => {
setTypingUsers(payload.users)
})
.subscribe()
async function notifyTyping() {
await channel.send({
type: 'broadcast',
event: 'typing',
payload: { users: [username] }
})
}
Bonnes Pratiques Realtime
- ✅ Toujours cleanup les channels dans le
useEffect return - ✅ Utiliser des filtres pour réduire le volume de données reçues
- ✅ Activer RLS sur les tables Realtime — les policies s’appliquent aux WS
- ✅ Utiliser Presence pour les indicateurs de connexion (pas de polling)
- ❌ Éviter d’écouter des tables très volumineuses sans filtre
- ❌ Ne pas créer plusieurs channels pour la même table sans raison
👉 Articles du guide Supabase
Cet article fait partie du Guide Complet Supabase 2026. Retrouvez les autres articles :
- ✅ Supabase : Le Guide Complet 2026
- ✅ Supabase vs Firebase : Comparatif Complet 2026
- ✅ Installer Supabase en Local avec Docker
- ✅ Supabase Pricing : Quel Plan Choisir en 2026
- ✅ Architecture Supabase : Postgres, GoTrue, Realtime et Storage
- ✅ Créer et Structurer sa Base de Données Supabase
- ✅ Supabase RLS : Sécuriser ses Données avec Row Level Security
- ✅ Supabase SQL : Triggers, Fonctions et Procédures Stockées
- ✅ Supabase Migrations : Gérer l’Évolution de son Schéma
- ✅ Supabase Auth : Email, OAuth et Magic Links
- ✅ Supabase Rôles et Permissions
- ✅ Supabase JWT : Comprendre les Tokens
- ✅ Supabase avec Next.js : App Router
- ✅ Supabase avec React : Hooks et Contexte
- ✅ API REST Supabase : Requêtes sans Backend
- ✅ Supabase Edge Functions : Serverless avec Deno
- 📅 Storage Supabase — à paraître le 30/06
- 📅 Vector & pgvector — à paraître le 02/07
- 📅 Supabase MCP — à paraître le 04/07
- 📅 Déploiement en production — à paraître le 06/07
- 📅 CLI Supabase — à paraître le 08/07


