Dejad de Llamar a Supabase "Firebase para Postgres". Es al Revés: un Motor de 35 Años que Absorbió Todo el Feature Set de Firebase
Cada vez que escucho "Supabase es el Firebase de Postgres", muero un poco.
Es la comparación al revés. La dirección real es la inversa: MySQL reinó en la web de los 2000, y luego Firebase convenció a una generación de que los documentos NoSQL eran el futuro. Pero PostgreSQL —ese motor "aburrido" de 35 años— ha absorbido en silencio todo lo que Firebase hacía especial: auth, realtime, storage, incluso búsqueda vectorial para IA.
Y la prueba no está en el marketing de Supabase.
Está en que si quitas PostgreSQL de debajo de cualquier feature "estrella" de Supabase, no queda nada. Quitas Postgres y no hay auth. No hay realtime. No hay vector search. El ceño fruncido de la comparación se apoya entero en una columna vertebral que es SQL puro y portable.
*El riesgo que cargas con Supabase no es el lock-in. Es lo contrario: que todo tu miedo va dirigido en la dirección equivocada. *
Empecemos por lo que la mayoría entiende mal.
El Argumento Convencional es una Falsa Dicotomía
El debate típico en 2026 se plantea así:
❌ "¿Quieres velocidad para el MVP? Usa Firebase o Supabase. ¿Quieres un backend serio para producción? Monta algo propio."
❌ "Supabase vale para hackathons. Nadie ejecuta producción sobre ella."
Ambos bandos fallan igual. Los dos tratan Supabase como un atajo del que te gradúas. Los dos ignoran que la premisa es exactamente la inversa.
✅ Supabase no es la opción fácil de la que te vas. Es el argumento de que PostgreSQL es el sitio de mayor apalancamiento para poner auth, realtime y lógica de IA.
Vamos a desmontarlo con evidencia, no con opiniones.
La Arquitectura Revela Dónde Está el Valor Real
Mira qué pasa bajo el capó cuando usas Supabase:
Auth (GoTrue) emite JWTs. Pero la *autorización no vive en un middleware. Vive en políticas de Row-Level Security* escritas en SQL directamente en la base de datos.
Realtime no es un websocket con un event-bus casero por encima. Se construye sobre logical replication de Postgres. Un mensaje de chat es literalmente una fila commiteada.
AI/vector search no requiere una base de datos vectorial aparte. Es una extensión (pgvector) y una columna con una query de similitud coseno escrita en SQL plano.
Storage, Edge Functions (Deno), PostgREST... todos son wrappers finos alrededor de Postgres y un stack open source bajo licencia Apache 2.0.
Cada feature de Supabase que te parece "magia" es una primitiva de Postgres con gabardina.
Eso tiene consecuencias que casi nadie comenta.
La Seguridad la Decide la Base de Datos, No tu API
Vengo de años escribiendo middlewares en Node/Express. Mi primer impulso fue proteger la base de datos desde la API. Supabase te obliga a un reset mental: *no estás protegiendo la base de datos de la API. La base de datos se protege a sí misma*.
Mira una política de RLS típica:
```sql
-- Creas una tabla de perfiles cuyo dueño es el usuario autenticado
CREATE TABLE profiles (
id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
username TEXT UNIQUE NOT NULL,
avatar_url TEXT
);
-- Activas RLS ANTES de escribir tu primera línea de app code
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
El `auth.uid()` lo sustituye Postgres por el ID del JWT que firmó GoTrue. Esas políticas se ejecutan tanto si el cliente es tu web, tu app móvil o una conexión directa de psql a la base. Un solo sitio decide seguridad, y se aplica uniformemente en cada superficie.
Esta es la demo de un signup con auth y un trigger que crea la fila de perfil automáticamente, para que identidad y datos de usuario jamás deriven:
```sql
-- Trigger que crea el perfil al registrarse
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO public.profiles (id, username)
VALUES (new.id, split_part(new.email, '@', 1));
RETURN new;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER on_auth_user_created
AFTER INSERT ON auth.users
FOR EACH ROW EXECUTE FUNCTION public.handle_new_user();
```
El "modelo de seguridad" de tu app es SQL que vive en una migración versionada. No es middleware que puedas esquivar con una petición directa a la base.
Realtime es la Prueba de fuego de que Entiendes la Plataforma
El realtime de Supabase te enseña más de Postgres que cualquier tutorial.
Se construye sobre logical replication y cambios en el WAL. Cuando ves un mensaje nuevo en tu chat, no es un evento de un broker independiente: es una fila que Postgres commiteó. Eso tiene dos consecuencias prácticas.
Una, buena: los eventos realtime son transaccionales. No recibes eventos de datos que no llegaron a commitearse. Es más robusto que una capa casera de WebSocket + event-bus donde un mensaje puede perderse entre el write y el publish.
```js
// Suscripción a cambios reales de la base, no a un mensajero artificial
const channel = supabase
.channel('todos-changes')
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'todos'
}, (payload) => {
console.log('Fila commiteada:', payload.new);
})
.subscribe();
```
Dos, la que casi nadie discute: pagas por cada write que replicas. Una suscripción ingenua sobre una tabla caliente multiplica la carga en el WAL y en los canales de replica. El gotcha clásico de escalado es ver que el realtime "va lento" y no entender que *tu query INSERT* es el cuello de botella. Suscríbete solo a las tablas y eventos que la interfaz necesita. Nada más.
El SDK es un Cliente Fino sobre Semántica SQL — y Eso es tu Mejor Amigo (o tu Peor Pesadilla)
Aquí está la comparación que casi ningún análisis superficial hace.
Firebase te obliga a adoptar su modelo de documentos NoSQL desde el día uno. Su SDK es el modelo mental. Nunca escribes una query SQL. Nunca haces un JOIN. Supabase es lo contrario: su SDK es un cliente fino que envuelve una API REST (PostgREST) que a su vez traduce a SQL. Y puedes verlo:
```js
// supabase-js: operación CRUD
const { data, error } = await supabase
.from('todos')
.insert({ task: 'Aprender RLS', user_id: userId })
.select();
// Lo que ocurre por debajo: una petición REST a PostgREST
// POST /rest/v1/todos
// Body: { "task": "Aprender RLS", "user_id": "..." }
// Headers: { "Content-Type": "application/json", "Authorization": "Bearer <JWT>" }
```
Demistifica la "magia": un `.insert().select()` es una petición HTTP a un endpoint auto-generado que aplica tus políticas RLS antes de tocar una fila.
El SDK de Supabase es una capa fina sobre semántica SQL. Eso lo convierte en la elección perfecta si ya piensas en términos relacionales, y en la peor elección posible si nunca quieres escribir una cláusula WHERE. Un artículo honesto tiene que decirlo: el marco de "Firebase killer" halaga a Supabase mientras oculta sus trade-offs ergonómicos reales.
pgvector Colapsa Toda una Clase de Decisiones de "Infraestructura IA"
Para productos en fase temprana, pgvector elimina la necesidad de una base de datos vectorial aparte.
Añades una extensión, una columna, y lanzas una query de similitud con JOINs SQL normales hacia tus filas relacionales:
```sql
-- Activas la extensión y creas la columna de embeddings
CREATE EXTENSION IF NOT EXISTS vector;
ALTER TABLE documents ADD COLUMN embedding vector(1536);
-- Búsqueda híbrida: los documentos más cercanos de este usuario, en este workspace
SELECT d.id, d.title,
d.embedding <=> $1 AS distancia
FROM documents d
JOIN workspaces w ON w.id = d.workspace_id
WHERE d.owner_id = auth.uid()
ORDER BY d.embedding <=> $1
LIMIT 10;
```
El gancho práctico: queries híbridas tipo "los documentos más cercanos de este usuario, filtrados por su workspace" son dolorosas entre dos sistemas distintos y triviales dentro de Postgres.
Pero anota el matiz: a muy gran escala, los motores vectoriales dedicados tienen perfiles de rendimiento distintos. Esto es una simplificación arquitectónica, no una verdad universal. Para tu producto en fase temprana, es la decisión correcta.
Para mover la generación de embeddings fuera del navegador, sácala a una Edge Function de Deno:
```ts
// Edge Function (Deno): genera y guarda el embedding sin exponer secretos
Deno.serve(async (req) => {
const { content, docId } = await req.json();
const res = await fetch("https://api.openai.com/v1/embeddings", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${Deno.env.get("OPENAI_API_KEY")}`,
},
body: JSON.stringify({ model: "text-embedding-3-small", input: content }),
});
const { data } = await res.json();
await supabase.from("documents")
.update({ embedding: data[0].embedding })
.eq("id", docId);
return new Response("ok", { status: 200 });
});
```
Secretos y compute pesado nunca llegan al navegador. Es Postgres puro por debajo.
El Framework que Propongo: El Patrón Schema-First con RLS como Fuente de Verdad
Aquí está el método que aplico en cada build que hago con Supabase. Lo llamo El Patrón Schema-First con RLS como Fuente de Verdad, y funciona así:
Paso 1 — Diseña el esquema en SQL puro ANTES de tocar tu app code.
Tablas, constraints, índices, claves foráneas. La carpeta de migraciones es la fuente de verdad. Cada feature de Supabase cuelga de la base de datos, así que si el esquema está mal, todo lo demás se arrastra mal.
Paso 2 — Activa ROW LEVEL SECURITY en cada tabla y escribe políticas explícitas con `USING` y `WITH CHECK`.
Referencia `auth.uid()` directamente. Verifica con un rol que no sea el owner antes de construir cualquier interfaz. Si no puedes leer tu propia fila con un rol distinto al dueño, no toques una sola línea de React.
Paso 3 — Conecta Auth al esquema con triggers.
Crea la fila de profile en el signup (como en el snippet de arriba) para que identidad y datos de usuario jamás deriven. Nunca sincronices a mano desde el cliente.
Paso 4 — Adopta realtime de forma selectiva.
Suscríbete solo a las tablas y eventos que la UI necesita. Apóyate en los change data de Postgres, no en polling del cliente. Recuerda: cada replicación cuesta, así que no repliques tablas calientes por costumbre.
Paso 5 — Para features de IA, empieza con una columna pgvector.
Guarda los embeddings junto a las filas fuente. Mueve la generación de embeddings a una Edge Function (Deno) para que los secretos y el compute pesado jamás lleguen al navegador.
El Lock-In no Existe. Pero las Respuestas Honestas a tus Objeciones Sí
Vamos con las tres objeciones que sé que estáis pensando.
"Supabase vale para un hackathon, pero nadie ejecuta producción sobre ella."
El core es PostgreSQL gestionado con tooling estándar — pg_dump, psql, migraciones versionadas. El stack open source (Postgres, GoTrue, Realtime, Storage, PostgREST, Edge Functions) es autohospedable y se usa en producción. Lo que sí debes dimensionar honestamente son los techos operativos del servicio gestionado: límites de conexiones, multi-región y fan-out de realtime muy grande. Ahí, tu opción de salida ya está definida desde el día cero.
"RLS es listo, pero mi equipo no piensa en SQL, y acoplar auth a políticas de base de datos es rígido."
La curva de aprendizaje es real. Pero existe un workflow de depuración: ejecuta tus queries como el rol autenticado y ve qué devuelve. Y las políticas pueden saltarse deliberadamente con flujos service-role para operaciones server-side. El modelo no es tan inflexible como parece a primera vista.
"Si Supabase es solo Postgres, ¿por qué no gestiono Postgres yo mismo con un backend de Node pequeño?"
Concesión total — y que sea la última jugada del artículo. El valor de Supabase no es un motor propietario: es un bundle mantenido de features de Postgres difíciles de operar (realtime, storage, auth, edge compute). La respuesta honesta es que, en el momento en que tu carga operativa supere tu velocidad de features, el exit con Postgres estándar es exactamente por qué la elección fue segura.
*Empiezas en Postgres. Supabase solo pasa a ser el wrapper mejor mantenido que existe alrededor de él. *
El Veredicto Final
La mejor llamada de Supabase no es su tecnología. Es la honestidad de su apuesta: no venderte un motor propietario bonito, sino decirte que el motor más aburrido y probado de la industria es ahora el sitio de mayor apalancamiento para tu auth, tu realtime y tu lógica de IA.
El 90% del miedo a Supabase es miedo al lock-in dirigido hacia el sitio equivocado. No estás atado a un ecosistema cerrado; estás escribiendo SQL portable sobre un motor de 35 años con una comunidad imposible de ignorar.
Cuando encuentres el techo operativo del servicio gestionado —y lo encontrarás—, tu salida es un volcado estándar, no un rewrite de diez semanas.
La pregunta en 2026 no es "¿Firebase o Supabase?".
Es "¿cuándo vais a dejar de tratar Postgres como la base de datos y empezar a tratarla como la capa de aplicación que ya es?"
Lee el artículo completo en brianmenagomez.com
Más sobre mis servicios en brianmenagomez.com
Herramientas: Conversor IAE CNAE · Gestorias cerca de ti · Calculadora IRPF

