Supabase en Producción: La Arquitectura que el 90% de Developers Ignora

Programación· 4 min de lectura

La Mayoría Usa Supabase Como si Fuera un Google Sheets con API

Conectas la base de datos. Haces un select('*') desde el cliente. Y llamas eso producción.

Es el error más común — y el más caro en términos de seguridad y rendimiento.

El verdadero Supabase no es tu base de datos. Es tu backend completo.

Postgres + autenticación + Realtime + Storage + Edge Functions. Todo integrado. Todo tipado. Todo con RLS nativo.

Si solo usas Supabase para hacer queries desde el cliente sin Row Level Security activado, estás exponiendo tu base de datos entera a cualquier usuario autenticado.

Este artículo te muestra la arquitectura correcta.

---

El Error Arquitectónico que Destruye Proyectos en Producción

El patrón malo es sorprendentemente común:

Approach incorrecto:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Approach correcto con RLS:

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop
[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Row Level Security es la característica más importante de Supabase. Y la más ignorada.

No es opcional. No es una optimización. Es la diferencia entre una app segura y una brecha de datos.

---

La Arquitectura de Autenticación que Realmente Funciona

La mayoría implementa auth de Supabase como si fuera Firebase Auth: login, logout, y poco más.

El auth real de Supabase es un sistema de identidad completo con JWT custom claims.

Paso 1: Configura el cliente con tipado completo

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Paso 2: Genera los tipos automáticamente

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Esto es crítico. Con los tipos generados, TypeScript te avisa en compile time cuando una query es incorrecta.

Paso 3: Server-side auth en Next.js con SSR

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

El patrón de createRouteHandlerClient vs createClient no es un detalle menor. Es la diferencia entre auth que funciona en producción y auth que falla silenciosamente con SSR.

---

Realtime: El Caso de Uso Correcto (y los Incorrectos)

Supabase Realtime es potente. También es el origen del 80% de los problemas de rendimiento en apps de producción.

El real problema del Realtime no es técnico. Es que los developers lo usan para todo cuando debería usarse para poco.

Cuándo NO usar Realtime:

→ Dashboards con datos que cambian cada hora

→ Perfiles de usuario que el propio usuario edita

→ Listas de productos en un e-commerce

→ Cualquier cosa que no necesite actualización en tiempo real

Cuándo SÍ usar Realtime:

→ Chat y mensajería

→ Notificaciones push en tiempo real

→ Colaboración simultánea (tipo Figma o Notion)

→ Indicadores de presencia ("3 usuarios leyendo esto")

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

El filter en Realtime no es opcional. Sin filtro, cada INSERT en la tabla dispara el listener para todos los usuarios conectados. Eso es un problema de rendimiento garantizado.

---

Edge Functions: Tu Backend Sin Servidor

Las Supabase Edge Functions corren en Deno. No en Node.js. Ese detalle importa.

El caso de uso correcto: lógica que no debe ejecutarse en el cliente y no necesita un servidor dedicado.

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

Nota el uso de SUPABASE_SERVICE_ROLE_KEY en las Edge Functions. Esta key bypassa RLS intencionalmente — úsala solo en server-side, nunca en el cliente.

---

Optimización de Queries: Postgres es tu Ventaja

El real Supabase no es Firebase con SQL. Es Postgres completo.

Eso significa que puedes usar todo lo que Postgres ofrece: índices parciales, funciones, triggers, views materializadas.

[@portabletext/react] Unknown block type "code", specify a component for it in the `components.types` prop

La mayoría de developers que usan Supabase nunca toca SQL directo. Dejan rendimiento enorme sobre la mesa.

---

El Stack Completo: Cómo Conectar Todo

Supabase funciona mejor como núcleo de un stack específico:

Next.js 15+ para el frontend con App Router

Supabase Auth para autenticación con OAuth y magic links

Supabase Storage para archivos con políticas RLS nativas

Supabase Edge Functions para webhooks y lógica server-side

Resend para emails transaccionales desde Edge Functions

Supabase Realtime solo donde necesites updates en tiempo real

Este stack elimina la necesidad de un backend separado en el 90% de los proyectos SaaS.

---

Takeaways Clave

RLS no es opcional. Actívalo en cada tabla desde el primer día.

Genera los tipos con `supabase gen types`. TypeScript te salva de errores en producción antes de que lleguen a producción.

Usa `createRouteHandlerClient` en Next.js. El cliente genérico no funciona correctamente con SSR.

Filtra siempre en Realtime. Un listener sin filtro en una tabla grande destruye el rendimiento.

`SUPABASE_SERVICE_ROLE_KEY` solo en server-side. Nunca en el cliente. Nunca en variables NEXT_PUBLIC_.

Aprovecha Postgres completo. Índices, triggers, views materializadas. Eso es lo que te diferencia de Firebase.

Supabase no es una base de datos en la nube. Es el backend completo que no tienes que construir.

La diferencia entre un proyecto que escala y uno que colapsa bajo carga está en estos patrones. No en el framework. No en el hosting. En cómo usas las herramientas que ya tienes.

Brian Mena

Brian Mena

Ingeniero informatico construyendo productos digitales rentables: SaaS, directorios y agentes de IA. Todo desde cero, todo en produccion.

LinkedIn