Supabase ofrece una configuración de backend sólida: Postgres, autenticación, almacenamiento y suscripciones en tiempo real, todo en un solo lugar. Se conecta con un marco de frontend sin problemas, lo que te permite desplegar y enviar rápidamente. No hay necesidad de las travesuras de Docker Compose, el bloqueo de Firebase o pesadillas operativas.
Foto: Growtika en Unsplash
Para quién es esto: Fundadores solitarios que crean MVPs. Necesitan un backend listo para producción hoy, no un clúster de Kubernetes en seis meses. Saben JavaScript o TypeScript y han lanzado al menos un proyecto secundario. Están cansados de juntar cinco servicios de AWS solo para gestionar datos de usuarios y restablecer contraseñas.
Paso 1: Crea un Proyecto Supabase y Obtén tus Claves
Regístrate en supabase.com, inicia un nuevo proyecto, elige una región cercana a tus usuarios y selecciona una contraseña de base de datos fuerte. Supabase configura una instancia dedicada de Postgres: un verdadero Postgres 15 con pgvector, no una imitación NoSQL.
Obtén la URL de tu proyecto y la clave pública anon en Configuración → API. Estas son las únicas variables de entorno del frontend que necesitas. La clave anon es segura del lado del cliente porque Supabase aplica políticas de seguridad a nivel de fila (RLS) en Postgres, limitando las solicitudes por el JWT del usuario autenticado.
Almacénalas en .env.local:
VITE_SUPABASE_URL=https://yourproject.supabase.co
VITE_SUPABASE_ANON_KEY=eyJhbGc...your-anon-key
El nivel gratuito proporciona 500 MB de base de datos, 1 GB de almacenamiento de archivos y 2 GB de ancho de banda, suficiente para probar una idea con usuarios reales. Según los precios de Supabase, cuesta $25/mes más allá de esos límites, con 8 GB de base de datos y 100 GB de ancho de banda en Pro.
Paso 2: Configura tu Frontend con Vite y React
Foto: Igor Miske en Unsplash
Se eligió Vite + React por su velocidad: no necesitas componentes de servidor de Next.js solo para leer filas de la base de datos. Configura el proyecto:
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install @supabase/supabase-js
Inicializa el cliente de Supabase en src/lib/supabase.ts:
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY
export const supabase = createClient(supabaseUrl, supabaseAnonKey)
Este cliente gestiona tokens de autenticación, actualización de sesiones y conexiones WebSocket para tiempo real. Impórtalo donde sea necesario para la base de datos o la autenticación.
Paso 3: Construye Flujos de Autenticación (Email/Contraseña y Enlace Mágico)
Supabase Auth utiliza GoTrue, el mismo servicio del que depende Netlify Identity. Proporciona autenticación por email/contraseña, enlaces mágicos, OAuth (Google, GitHub, etc.) y autenticación por teléfono.
Crea un componente de registro:
import { useState } from 'react'
import { supabase } from './lib/supabase'
export function SignUp() {
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const [loading, setLoading] = useState(false)
const handleSignUp = async (e: React.FormEvent) => {
e.preventDefault()
setLoading(true)
const { error } = await supabase.auth.signUp({ email, password })
if (error) alert(error.message)
else alert('Revisa tu email para el enlace de confirmación')
setLoading(false)
}
return (
<form onSubmit={handleSignUp}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Contraseña"
/>
<button disabled={loading}>Registrarse</button>
</form>
)
}
Usando el enlace mágico (sin contraseña):
const { error } = await supabase.auth.signInWithOtp({ email })
Supabase envía el email, el usuario hace clic en el enlace y regresa a tu aplicación con una sesión válida. Sin configuración SMTP, sin claves API de SendGrid, sin plantillas de email en tu repositorio.
Para verificar el estado de autenticación:
import { useEffect, useState } from 'react'
import { supabase } from './lib/supabase'
import { Session } from '@supabase/supabase-js'
export function useSession() {
const [session, setSession] = useState<Session | null>(null)
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session)
})
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => {
setSession(session)
}
)
return () => subscription.unsubscribe()
}, [])
return session
}
Ahora, restringe rutas o componentes basados en session?.user.
Paso 4: Crea Tablas y Habilita la Seguridad a Nivel de Fila
En el panel de control de Supabase → Editor de Tablas → Nueva Tabla, crea una tabla todos:
id(int8, clave primaria, auto-incremento)user_id(uuid, referencia aauth.users(id))task(texto)completed(bool, por defecto falso)created_at(timestamptz, por defecto ahora())
Haz clic en Guardar. Habilita RLS en Autenticación → Políticas, y haz clic en Habilitar RLS en todos.
Agrega una política para que los usuarios solo puedan leer sus filas:
CREATE POLICY "Los usuarios pueden ver sus propios todos"
ON todos FOR SELECT
USING (auth.uid() = user_id);
Agrega una política de inserción:
CREATE POLICY "Los usuarios pueden insertar sus propios todos"
ON todos FOR INSERT
WITH CHECK (auth.uid() = user_id);
Agrega políticas de actualización/eliminación de manera similar. Sin RLS, la clave anon expondría todas las filas; RLS es lo que hace que Supabase sea seguro por defecto.
Paso 5: Consulta Datos desde React
Obtén los todos:
import { useEffect, useState } from 'react'
import { supabase } from './lib/supabase'
export function TodoList({ userId }: { userId: string }) {
const [todos, setTodos] = useState<any[]>([])
useEffect(() => {
const fetchTodos = async () => {
const { data, error } = await supabase
.from('todos')
.select('*')
.eq('user_id', userId)
.order('created_at', { ascending: false })
if (error) console.error(error)
else setTodos(data)
}
fetchTodos()
}, [userId])
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.task}</li>
))}
</ul>
)
}
Inserta un nuevo todo:
const { error } = await supabase
.from('todos')
.insert({ user_id: session.user.id, task: 'Enviar MVP' })
if (error) console.error(error)
El cliente de Supabase utiliza PostgREST, proporcionando puntos finales REST automáticos para cada tabla. El constructor de consultas son simplemente solicitudes HTTP vestidas con sintaxis.
Paso 6: Agrega Suscripciones en Tiempo Real
El tiempo real funciona como un canal WebSocket, escuchando el flujo de replicación de Postgres. Habilítalo en Base de Datos → Replicación, y activa la tabla todos.
Suscríbete a inserciones:
useEffect(() => {
const channel = supabase
.channel('todos')
.on(
'postgres_changes',
{ event: 'INSERT', schema: 'public', table: 'todos', filter: `user_id=eq.${userId}` },
(payload) => {
setTodos((prev) => [payload.new, ...prev])
}
)
.subscribe()
return () => {
supabase.removeChannel(channel)
}
}, [userId])
Ahora, cuando otra pestaña (o usuario, si es una aplicación colaborativa) inserta una fila, tu interfaz se actualiza instantáneamente. Sin sondeos, sin servidor Socket.io necesario.
El tiempo real es gratuito en el nivel básico. Según la documentación de Supabase, ofrece 2 millones de mensajes mensuales en el plan gratuito, 5 millones en Pro.
Paso 7: Despliega en Vercel o Netlify
Sube tu repositorio a GitHub, luego impórtalo en Vercel o Netlify. Agrega las dos variables de entorno (VITE_SUPABASE_URL y VITE_SUPABASE_ANON_KEY) en el panel de control. Despliega.
Eso es todo. No hay necesidad de una imagen de Docker, instancia EC2 o configuración de CI/CD. Vercel maneja la construcción de Vite, sirve archivos estáticos desde CDN, y tu aplicación accede directamente a las APIs de Supabase desde el navegador.
¿Necesitas funciones sin servidor (por ejemplo, webhooks de Stripe, trabajos programados)? Tanto Vercel como Netlify las admiten. Pero, honestamente, para la mayoría de las aplicaciones CRUD, no las necesitarás; Supabase Postgres con RLS lo cubre todo.
Lo Que Nadie Te Dice Sobre Supabase en Producción
El agrupamiento de conexiones se convierte en un desafío después de 100K usuarios. El nivel gratuito da 60 conexiones concurrentes de Postgres. Abrir una conexión por solicitud API lo agotará rápidamente. Usa el agrupador de conexiones de Supabase (Supavisor) en planes de pago, o cambia a Prisma Data Proxy si estás en un entorno sin servidor.
Las políticas de RLS pueden afectar el rendimiento de las consultas. ¿Escribiendo una política como user_id = auth.uid()? Postgres no puede usar un índice a menos que user_id sea la primera columna en un índice compuesto. Analiza las consultas con EXPLAIN ANALYZE en el editor SQL. A veces, RLS puede convertir una consulta de 10 ms en una de 300 ms con 500K filas.
El almacenamiento opera como S3 con un catálogo de Postgres. Supabase Storage no son columnas BYTEA de Postgres; es almacenamiento de objetos con una tabla de Postgres para el seguimiento de metadatos. Para avatares de usuario o PDFs, está bien. Para una plataforma de videos, considera Cloudflare R2 o Backblaze B2 para un egreso más económico.
Los límites de tasa de autenticación son estrictos. Supabase limita los correos electrónicos de registro y restablecimiento de contraseña para prevenir abusos. En el nivel gratuito, solo se permiten 4 correos electrónicos por hora por usuario. ¿Construyendo una lista de espera con verificación de email? Alcanzarás el límite. Usa un proveedor SMTP personalizado (a través de la configuración de Supabase Auth) o restringe los registros con un código de invitación.
El desarrollo local necesita Docker. Supabase CLI (npx supabase init) inicia un stack local de Postgres, GoTrue, PostgREST y Realtime en Docker. Excelente para pruebas de migración, pero requiere Docker. Si usas Windows sin WSL2, podría ser problemático.
Errores Comunes al Lanzar con Supabase
Descuidar las restricciones de clave foránea user_id. Sin hacer cumplir REFERENCES auth.users(id) ON DELETE CASCADE, las filas huérfanas podrían acumularse cuando los usuarios eliminan cuentas. Supabase no las limpiará automáticamente.
Exponer la clave service_role del lado del cliente. La clave anon respeta RLS, pero la clave service_role omite RLS y tiene acceso total de administrador. Nunca la coloques en el código del frontend o en .env.local; úsala solo en funciones sin servidor o scripts de backend.
Ignorar la confirmación de email en producción. Supabase por defecto no requiere confirmación de email al registrarse. Actívala en Autenticación → Plantillas de Email con "Confirmar registro". De lo contrario, cualquiera podría registrarse con admin@tuempresa.com y acceder por fuerza bruta.
Saltar copias de seguridad de la base de datos. El nivel gratuito no incluye copias de seguridad automáticas. En Pro, se proporcionan copias de seguridad diarias durante siete días. ¿Almacenando datos de ingresos? Actualiza o configura trabajos cron de pg_dump a S3.
Codificar la clave anon en aplicaciones móviles. Aunque la clave anon es "pública", cámbiala si se filtra. Usa claves específicas para entornos (dev, staging, prod) y evita comprometerlas en Git.
Preguntas Frecuentes
¿Puedo usar Supabase con Next.js App Router?
Sí, de hecho. Instala @supabase/ssr y sigue la guía oficial de Next.js. Se necesita middleware para actualizar tokens del lado del servidor y pasar sesiones a los controladores de rutas. Implica más código boilerplate que la autenticación del lado del cliente, pero funciona de manera efectiva.
¿Supabase admite GraphQL?
No existe soporte nativo para GraphQL. Supabase utiliza PostgREST (REST) y Realtime (WebSocket). Puedes agregar una extensión pg_graphql y exponer un endpoint de GraphQL, pero no está oficialmente soportado. ¿Necesitas GraphQL? Considera Hasura con tu propio Postgres o Firebase.
¿Cómo ejecuto migraciones y lleno datos?
Utiliza Supabase CLI. Crea una migración: npx supabase migration new add_todos_table. Escribe SQL en supabase/migrations/. Aplica con npx supabase db push. Para datos de prueba, incluye SQL en supabase/seed.sql y ejecuta npx supabase db reset. Las migraciones están controladas por versiones y se aplican automáticamente en staging/prod a través de GitHub Actions.
¿Qué pasa si supero a Supabase?
Tú eres el propietario de tu base de datos Postgres. Exórtala con pg_dump e impórtala a RDS, Cloud SQL o un host de Postgres gestionado. Perderás la autenticación de GoTrue y Realtime, pero tus datos y esquema seguirán siendo portátiles. Supabase no es un bloqueo de proveedor: es Postgres con comodidad añadida.
Conclusión: Lanza Hoy, Escala Mañana
En la práctica, Supabase te permite pasar de cero a una aplicación web desplegada en un fin de semana. La autenticación, la base de datos, el almacenamiento de archivos y el tiempo real se configuran con solo dos variables de entorno y sin código de backend. Si estás validando una idea, este es tu camino más rápido hacia un producto funcional.
Próximo paso: Elige una idea, crea un proyecto en Supabase, configura la autenticación y una tabla, luego despliega en Vercel. Hazlo este fin de semana. ¿Por qué esperar? Lanza antes de estar listo: a los usuarios no les importa si tus políticas de RLS aún no son perfectas. Para más información sobre cómo desplegar tu aplicación, consulta nuestra comparación de Vercel vs. Netlify: ¿Cuál es mejor para fundadores solitarios? y aprende cómo Lanzar tu primera API usando FastAPI en 7 días.
Nota editorial: Este artículo fue elaborado con asistencia de IA y revisado por Javier Valencia. A lo largo del texto se distinguen los hechos verificados de la opinión editorial. Las fuentes externas enlazadas son independientes de NewsTide.