Volver al blog
Supabase en producción: lo que nadie te cuenta
Databases 12 de mayo de 2025 11 min de lectura

Supabase en producción: lo que nadie te cuenta

Llevamos Supabase en múltiples proyectos activos. Aquí va lo que aprendimos: RLS bien hecho, Realtime sin memory leaks, auth multi-método y los límites reales del plan gratuito.

BKLN Software

Equipo de desarrollo de BKLN Software & Systems.

Por qué usamos Supabase

En BKLN llevamos Supabase en producción en varios proyectos distintos: un marketplace C2C, una plataforma de citas, un sistema de gestión escolar y una web corporativa con formularios. No es una elección casual — es la herramienta que mejor equilibra productividad, control y coste para el tipo de proyectos que construimos.

Pero Supabase tiene matices que la documentación no siempre cubre. Aquí va lo que hemos aprendido.

Row Level Security: hazlo bien desde el principio

RLS es la característica que más confunde a los equipos que vienen de Firebase. En Firebase el control de acceso está en reglas de seguridad separadas del esquema. En Supabase vive directamente en PostgreSQL.

La tentación cuando estás en desarrollo es deshabilitar RLS para ir más rápido. No lo hagas. Es mucho más difícil añadirlo después que diseñarlo desde el principio.

El patrón que usamos en todos nuestros proyectos:

-- Habilitar RLS en todas las tablas de usuario
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;

-- Los usuarios solo ven sus propios mensajes
CREATE POLICY "usuarios_ven_sus_mensajes"
ON messages FOR SELECT
USING (
  auth.uid() = sender_id OR
  auth.uid() = receiver_id
);

-- Solo el emisor puede insertar
CREATE POLICY "usuarios_insertan_sus_mensajes"
ON messages FOR INSERT
WITH CHECK (auth.uid() = sender_id);

El error más común: olvidar que RLS se aplica también a los Realtime subscriptions. Si tienes una política restrictiva en SELECT, tu canal de Realtime solo recibirá los cambios que esa política permite. Esto es bueno para seguridad, pero puede crear confusión si no lo sabes.

Realtime sin memory leaks

Supabase Realtime es potente pero requiere gestión manual de suscripciones. Si abres canales sin cerrarlos, acumulas conexiones que consumen recursos en cliente y servidor.

En JavaScript puro (sin React hooks para hacer cleanup automático), el patrón que seguimos:

let activeChannel = null

function suscribirseAConversacion(conversationId) {
  // Limpiar canal anterior si existe
  if (activeChannel) {
    supabase.removeChannel(activeChannel)
    activeChannel = null
  }

  activeChannel = supabase
    .channel(`conv:${conversationId}`)
    .on('postgres_changes', {
      event: 'INSERT',
      schema: 'public',
      table: 'messages',
      filter: `conversation_id=eq.${conversationId}`
    }, handleNuevoMensaje)
    .subscribe()
}

// Al salir de la vista
function limpiar() {
  if (activeChannel) {
    supabase.removeChannel(activeChannel)
    activeChannel = null
  }
}

La regla: por cada channel() que abres, tienes que tener un removeChannel() cuando ya no lo necesitas.

Auth multi-método sin complejidad

Supabase Auth soporta email/contraseña, magic link, OAuth (Google, GitHub, etc.) y OTP por SMS. El truco es que todos comparten la misma sesión — no tienes que gestionar múltiples sistemas de autenticación.

Lo que sí tienes que gestionar: el flujo de onboarding tras el primer login. Con OAuth, el usuario llega con email pero sin los datos de perfil que necesitas. El patrón que usamos es un trigger en PostgreSQL:

CREATE OR REPLACE FUNCTION crear_perfil_usuario()
RETURNS TRIGGER AS $$
BEGIN
  INSERT INTO perfiles (id, email, creado_en)
  VALUES (NEW.id, NEW.email, NOW())
  ON CONFLICT (id) DO NOTHING;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER al_crear_usuario
  AFTER INSERT ON auth.users
  FOR EACH ROW EXECUTE FUNCTION crear_perfil_usuario();

Así, independientemente del método de login, siempre tienes un perfil disponible inmediatamente.

Los límites reales del plan gratuito

El plan gratuito de Supabase es generoso para desarrollo y proyectos pequeños, pero tiene límites que conviene conocer antes de lanzar:

  • 500 MB de base de datos — suficiente para empezar, limitante si guardas archivos o logs en la DB
  • 2 GB de ancho de banda — el más fácil de alcanzar si sirves imágenes desde Supabase Storage
  • 50.000 usuarios activos mensuales — difícilmente un problema al principio
  • Proyectos en pausa tras 7 días de inactividad — esto sí es molesto en desarrollo

Para proyectos en producción con tráfico real, el plan Pro (25$/mes) es la opción correcta. Pero para MVP, el plan gratuito da para mucho más de lo que parece.

Nuestra valoración después de varios proyectos

Supabase es la mejor opción que conocemos para proyectos donde quieres una base de datos PostgreSQL real (con todas sus capacidades: funciones, triggers, índices, full-text search) sin gestionar infraestructura.

La curva de aprendizaje de RLS es real, pero vale la pena. Una vez que lo entiendes, te da un nivel de control sobre quién accede a qué que Firebase simplemente no tiene.

¿Lo usaríamos para un proyecto de millones de usuarios? Dependería del caso. Para los proyectos que construimos — aplicaciones de negocio, plataformas de nicho, sistemas de gestión — es exactamente la herramienta que necesitamos.

SupabasePostgreSQLRLSRealtimeAuth

¿Necesitas ayuda técnica?

Construimos lo que necesitas.

Aprende más

Cursos prácticos en español.