Cuando arrancamos KEYON Access en septiembre de 2025, dedicamos una semana completa a elegir backend. No era evaluación académica: teníamos mil doscientos alumnos esperando un sistema que llevaba meses de retraso, y cualquier decisión mala ahí se pagaba en refactoring de meses. El duelo real se dio entre Firebase (Google, modelo NoSQL, auth integrada) y Supabase (open source, Postgres, hype de 2024).
Ganó Firebase. Este artículo explica por qué — y cuándo elegiríamos Supabase en su lugar.
Los criterios de una escuela mexicana
No elegimos stacks abstractamente; elegimos para resolver restricciones concretas. Las nuestras eran:
- Auth multi-rol. Seis roles granulares: superadmin, admin escolar, prefecto, coordinador, capturista, visor. Cada uno con permisos diferentes sobre colecciones específicas.
- Realtime en kiosco. Cuando un alumno registra entrada, el panel de prefectura lo ve aparecer sin refresh.
- Offline-first. La red escolar se cae cinco a doce veces al día. El sistema no puede depender de internet permanente.
- Operación sin infra. No hay DevOps en el presupuesto. Queremos cero servidores que mantener.
- Costo menor a $500 MXN mensuales hasta llegar a 5,000 usuarios activos.
- LFPDPPP compliance. Datos personales en servidores con garantías legales.
Round 1: setup y DX
De las dos, Supabase se siente más moderna. Dashboard limpio, SQL editor integrado, auto-generación de tipos TypeScript directo desde la DB. Firebase Console se ve de 2018 y tiene fricción en tareas que deberían ser obvias (agregar un rol, debuggear reglas).
Pero la experiencia se voltea al tercer día, cuando dejas de admirar el dashboard y empiezas a hacer cosas reales. Firebase te permite hacer esto en dos líneas de cliente:
import { doc, onSnapshot } from "firebase/firestore";
const unsub = onSnapshot(doc(db, "alumnos", uid), (snap) => {
setAlumno(snap.data());
});Con Supabase, lo mismo requiere configurar canales de realtime, suscribirte a cambios específicos, y manejar la reconciliación cuando la red cae:
const channel = supabase
.channel('alumno-' + uid)
.on(
'postgres_changes',
{ event: '*', schema: 'public', table: 'alumnos', filter: 'uid=eq.' + uid },
(payload) => { setAlumno(payload.new); }
)
.subscribe();
// no olvides channel.unsubscribe() al desmontarAmbos funcionan, pero uno es un hook de tres líneas y el otro es un canal con ciclo de vida explícito. Para un equipo solo, el costo cognitivo se acumula.
Ganador: Firebase, por estrecho margen.
Round 2: auth y permisos por rol
Aquí Firebase gana feo. Los custom claims permiten pegarle a un usuario un objeto tipo { role: "prefecto", schoolId: "cbtis001" } y esos claims están disponibles en las reglas Firestore sin leer otra colección. Resultado: permisos en sub-milisegundos, sin queries adicionales, sin riesgo de fugas.
match /ingresos_cbtis/{id} {
allow read: if
request.auth.token.role in ["admin", "prefecto", "superadmin"]
&& request.auth.token.schoolId == resource.data.schoolId;
}En Supabase, las Row Level Security (RLS) policies son igual de potentes pero exigen un JOIN a la tabla de usuarios en cada query con permisos:
CREATE POLICY "admins see their school ingresos" ON ingresos
FOR SELECT USING (
school_id = (
SELECT school_id FROM usuarios WHERE id = auth.uid()
)
AND (
SELECT role FROM usuarios WHERE id = auth.uid()
) IN ('admin', 'prefecto', 'superadmin')
);El subquery se ejecuta por cada SELECT. Con índices bien puestos es barato, pero es ruido cognitivo y una fuente de bugs cuando cambias el esquema.
Custom claims en Firebase convierten la autorización en un operador de igualdad. RLS en Supabase la convierte en una query. Para sistemas con seis roles granulares, esa diferencia es arquitectura.
Ganador: Firebase, claro.
Round 3: offline-first
Este round Firebase lo gana sin pelear. La SDK de Firestore trae persistence local con IndexedDB out of the box. Activar modo offline es literalmente:
import { enableIndexedDbPersistence } from "firebase/firestore";
await enableIndexedDbPersistence(db);Los writes mientras no hay red se encolan, se reenvían cuando vuelve, y el cliente lee local mientras tanto. Sin que escribas un ciclo adicional.
Supabase no tiene nada equivalente nativo. Hay librerías de la comunidad (supabase-js-cache, @supabase-cache-helpers) pero son opt-in, tienen quirks, y no manejan sync automático. Implementar offline-first sobre Supabase significa construirlo tú con IndexedDB directo, una librería como dexie, y un sync loop que reconcilie. Dos semanas de trabajo y una fuente nueva de bugs.
Ganador: Firebase, sin discusión.
Round 4: costo a escala
Aquí Supabase tiene un argumento real. Firestore cobra por operaciones (lecturas, escrituras, borrados), y en un sistema con listeners en tiempo real puedes acumular millones de lecturas al mes sin darte cuenta. Un panel de prefectura con cinco usuarios suscritos a ingresos_cbtis durante ocho horas diarias puede generar 200k lecturas mensuales solo en idle.
Supabase cobra por fila almacenada y ancho de banda, no por operación. Una consulta que lee mil filas cuesta lo mismo que una que lee una. Para queries densas es dramáticamente más barato.
Números reales de KEYON (mil doscientos alumnos, CBTis No. 001, abril 2026):
Firebase Blaze (pay-as-you-go)
Lecturas ~430k/mes $0.18 MXN
Escrituras ~18k/mes $0.65 MXN
Storage 110 MB $0.05 MXN
Bandwidth ~2.1 GB incluido
Total: $0.88 MXN
Supabase (estimación equivalente, plan Pro)
Plan base $500 MXN (25 USD)
DB storage 110 MB incluido
Bandwidth 2.1 GB incluido
Auth users incluido
Total: $500 MXNEsta comparación es honesta para nuestro caso específico, pero no se extrapola. Firebase Blaze empieza baratísimo y se dispara no linealmente con escala. A 50 mil usuarios activos con patrones de lectura densos, Supabase sale más barato. El cross-over típico para SaaS escolares está alrededor de 8-10 planteles simultáneos. Antes de eso, Firebase. Después, reconsidera.
Con nuestros volúmenes actuales, Firebase cuesta centavos. Cuando KEYON llegue a 10 planteles y 15k usuarios concurrentes, vamos a reevaluar.
Ganador: depende de escala. Para nuestro caso actual: Firebase.
Round 5: compliance y residencia
LFPDPPP no exige residencia de datos en México, pero sí obliga a garantías de protección equivalentes o superiores a las nacionales. Ambos proveedores cumplen formalmente (ISO 27001, SOC 2), pero hay diferencias prácticas:
- Firebase permite elegir región
northamerica-northeast1(Montreal, Canadá) ous-central1(Iowa). Ambas con DPA (Data Processing Agreement) firmable. - Supabase ofrece instancias en AWS us-east-1, us-west-1, eu-central-1, etc. Con el plan Pro puedes pedir dedicated AWS instance con location específica. DPA disponible.
Para KEYON elegimos us-central1 de Firebase por latencia (más cercano que Montreal) y por el DPA de Google que cubre México explícitamente.
Ganador: empate técnico, Firebase por conveniencia.
Round 6: control y exit
Aquí Supabase gana, y es un argumento estratégico. Supabase es Postgres debajo. Si decides migrar en dos años, haces pg_dump y lo restauras en cualquier Postgres managed. Sales con todo: datos, schemas, funciones, policies.
Firestore es una base NoSQL propietaria. Migrar a Postgres requiere escribir exportadores custom, mapear colecciones a tablas, reconciliar la falta de joins, y reescribir toda la lógica de queries. Es factible pero caro.
Para KEYON este riesgo es bajo — es un sistema institucional donde cambiar backend implica un proyecto nuevo de todas formas. Para un SaaS comercial con mayor incertidumbre, Supabase da un seguro real.
Ganador: Supabase.
Veredicto: Firebase, con matices
Score final: Firebase 4, Supabase 1, empates 1. En nuestro caso específico — sistema institucional multi-rol con offline-first y escala moderada — Firebase ganó por el pipeline completo de auth+rules+realtime+offline siendo dramáticamente más simple de construir.
Pero Supabase no es peor. Es diferente. Hay casos reales donde elegiríamos Supabase sobre Firebase:
- Analytics pesado. Dashboards con queries agregadas complejas (SUM, JOIN, GROUP BY) sufren en Firestore, florecen en Postgres.
- Escala alta y costo-sensible. Productos con millones de lecturas mensuales desde el día uno.
- Relaciones fuertes. Dominios con muchos many-to-many (p. ej. facturación con líneas, impuestos, descuentos).
- Equipo con expertise SQL. Un DBA de Postgres rinde 10x en Supabase, inexistente en Firestore.
- Riesgo de lock-in inaceptable. Cuando perder acceso al backend es una amenaza existencial del negocio.
El takeaway
No elijas backend por ideología ("open source") ni por hype ("Supabase es el futuro"). Lista tus cinco restricciones reales, comparalas round por round con el stack candidato, y elige el que menos fricción genere en producción. En nuestro caso, con Firebase construimos un sistema de 12 módulos en ocho meses; con Supabase probablemente habría tomado diez o doce, con dos semanas más solo armando offline-first.
Si tienes un caso similar al nuestro — institución, multi-rol, offline-first — Firebase es la apuesta segura. Si estás en cualquier otro caso, arma tu propio match de seis rounds antes de decidir.