DEV Community

Sora2 Hub Team
Sora2 Hub Team

Posted on

Supabase Realtime en Next.js (App Router): 5 errores comunes y cómo evitarlos

Supabase Realtime permite que una app de Next.js reciba cambios de la base de datos al instante: un chat, un tablero de pedidos o un contador de notificaciones. Funciona muy bien en local, pero al pasar a producción aparecen siempre los mismos problemas. Estos son los cinco que más vemos y su solución.

1. Suscribirse desde un Server Component

Realtime abre un WebSocket en el navegador. Un Server Component se ejecuta una vez en el servidor y no mantiene conexiones, así que la suscripción nunca llega al cliente. La suscripción debe vivir en un componente con 'use client', y los datos iniciales pueden venir del servidor como props.

'use client'
import { useEffect, useState } from 'react'
import { createBrowserClient } from '@supabase/ssr'

export function Pedidos({ iniciales }: { iniciales: Pedido[] }) {
  const [pedidos, setPedidos] = useState(iniciales)

  useEffect(() => {
    const supabase = createBrowserClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
    )
    const canal = supabase
      .channel('pedidos')
      .on('postgres_changes',
        { event: 'INSERT', schema: 'public', table: 'pedidos' },
        (payload) => setPedidos((p) => [payload.new as Pedido, ...p]))
      .subscribe()

    return () => { supabase.removeChannel(canal) }
  }, [])

  return <ul>{pedidos.map((p) => <li key={p.id}>{p.titulo}</li>)}</ul>
}
Enter fullscreen mode Exit fullscreen mode

2. Olvidar limpiar el canal

Sin removeChannel en el cleanup del useEffect, cada navegación o recarga en caliente crea un canal nuevo. El resultado son eventos duplicados y, con el tiempo, el límite de conexiones del proyecto alcanzado. Limpia siempre el canal al desmontar.

3. No activar la publicación de la tabla

Por defecto las tablas no emiten cambios. Hay que añadirlas a la publicación supabase_realtime (en el panel: Database, Publications, o con SQL):

alter publication supabase_realtime add table public.pedidos;
Enter fullscreen mode Exit fullscreen mode

Si no llega ningún evento y no hay errores en consola, casi siempre es esto.

4. Esperar eventos que RLS bloquea

Realtime respeta las políticas de Row Level Security. Si el usuario no puede hacer select sobre una fila, tampoco recibirá su evento. Es lo correcto por seguridad, pero confunde cuando las políticas solo cubren insert. Revisa que exista una política de lectura para las filas que el cliente debe ver.

5. Filtrar en el cliente en lugar de en el canal

Recibir todos los cambios de la tabla y filtrarlos en JavaScript gasta ancho de banda y expone datos innecesarios. Usa el parámetro filter del canal:

{ event: '*', schema: 'public', table: 'mensajes', filter: `sala_id=eq.${salaId}` }
Enter fullscreen mode Exit fullscreen mode

Resumen

Suscripción solo en cliente, limpieza del canal, tabla añadida a la publicación, políticas de lectura correctas y filtros en el servidor. Con eso, Realtime se comporta igual en Vercel que en local.


Aviso: escribimos esto desde el equipo de Massvai, un generador de apps con IA que crea proyectos full-stack con Next.js, Supabase y Vercel. Los consejos sirven para cualquier proyecto, uses o no nuestra herramienta.

Top comments (0)