Primeros pasos con Supabase: backend integral con PostgreSQL + Auth + Storage

Mirando el duodécimo error de conexión a la base de datos en pantalla, quedó claro: para un desarrollador frontend, montar algo full stack es difícil.
Antes, cada función de backend implicaba aprender Node.js, Express, configurar la base de datos, la autenticación y el almacenamiento de archivos — cada pieza, un agujero distinto. Hasta que apareció Supabase.
En pocas palabras, es una alternativa open source a Firebase, pero con PostgreSQL en lugar de un NoSQL que da dolores de cabeza. Además empaqueta base de datos, autenticación y almacenamiento en un solo backend.
Este artículo te lleva desde cero con Supabase, centrado en Database, Auth y Storage. Al terminar deberías poder montar un backend completo sin pelearte con archivos de configuración.
Qué es Supabase
Empecemos por lo básico: qué es Supabase.
Es una plataforma BaaS, Backend as a Service — backend como servicio. Es decir, no montas servidores, no configuras la base de datos ni escribes APIs: ellos lo resuelven por ti.
A diferencia de Firebase, Supabase es totalmente open source. Y usa PostgreSQL, lo cual importa: es relacional, permite SQL complejo y relaciones de datos claras — mucho más práctico que Firestore documental.
Supabase tiene seis funciones principales:
- Database: base PostgreSQL con consultas SQL y REST API autogenerada
- Auth: autenticación con email, login social (Google, GitHub, etc.) y JWT
- Storage: almacenamiento de archivos, similar a AWS S3 pero más simple
- Realtime: sincronización en tiempo real, ideal para chat
- Edge Functions: computación en el edge, similar a AWS Lambda
- Vector Database: base vectorial para aplicaciones de IA
En este artículo nos centramos en las tres primeras: Database, Auth y Storage — el núcleo. El resto lo veremos más adelante.
Seguro te preguntas: open source, PostgreSQL, auth y storage… ¿mejor que Firebase? Lo detallamos después; en resumen: si necesitas SQL, relaciones complejas o control total de los datos, elige Supabase; si haces apps móviles con sincronización en tiempo real muy exigente, Firebase puede encajar mejor.
Primeros pasos
Crear un proyecto Supabase
Ve a supabase.com y regístrate. Luego pulsa «New Project» para crear un proyecto.
Al crearlo rellenarás:
- Nombre del proyecto: el que quieras, por ejemplo
my-first-app - Contraseña de la base de datos: anótala, la usarás después
- Región: la más cercana; desde China, Singapore o Tokyo suelen ir bien
En unos tres minutos estará listo. Verás el panel con el Dashboard y un menú a la izquierda: Table Editor, Authentication, Storage, Edge Functions… parece mucho, pero en este artículo lo iremos viendo.
Instalación e inicialización
Instala Supabase en tu proyecto frontend. Primero la dependencia:
npm install @supabase/supabase-js
Luego busca en el Dashboard de Supabase el Project URL y la Anon Public Key, en Settings > API.
Inicializa el cliente:
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = 'https://your-project-id.supabase.co';
const supabaseAnonKey = 'your-anon-public-key';
export const supabase = createClient(supabaseUrl, supabaseAnonKey);
Este código es la puerta de entrada a Supabase. Consultas, login y subida de archivos pasan por el objeto supabase.
Probar la conexión
Tras inicializar, comprueba que conecta. Lo más simple es consultar la base:
const { data, error } = await supabase.from('users').select('*');
if (error) {
console.error('Conexión fallida:', error.message);
} else {
console.log('¡Conexión correcta!', data);
}
Si dice que no existe la tabla users, es normal — aún no la has creado. En la siguiente sección lo vemos.
Errores habituales:
- URL o Key mal copiados: revisa que estén completos
- Error CORS: a veces hay que configurarlo en el frontend, aunque Supabase suele permitirlo por defecto
- Red: ocasionalmente falla; espera unos minutos y reintenta
Si todo va bien verás datos — quizá un array vacío [] si la tabla aún no tiene filas.
Database: operaciones con la base de datos
Aquí está el corazón de Supabase. Si conoces PostgreSQL te resultará familiar; si vienes del frontend y SQL te cuesta, el Table Editor visual te permite operar sin escribir SQL.
Crear tablas
Hay dos formas: Table Editor (visual) o SQL.
En el Dashboard, Table Editor → «Create a new table». Rellena nombre, campos y tipos.
Ejemplo, tabla users:
| Campo | Tipo | Restricciones |
|---|---|---|
| id | int8 | Primary Key, Auto Increment |
| text | Unique, Not Null | |
| name | text | - |
| created_at | timestamptz | Default: now() |
Pulsa «Save» y listo.
Para operaciones complejas, SQL suele ir más rápido. El SQL Editor está en el menú izquierdo del Dashboard.
SQL para users y projects:
-- Tabla de usuarios
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
name TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Tabla de proyectos
CREATE TABLE projects (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
title TEXT NOT NULL,
description TEXT,
status TEXT DEFAULT 'active',
created_at TIMESTAMPTZ DEFAULT NOW()
);
Detalle: user_id en projects es clave foránea de users.id. Cada proyecto pertenece a un usuario — ventaja de lo relacional.
Operaciones CRUD
Con las tablas creadas, prueba crear, leer, actualizar y borrar.
Insertar datos:
// Insertar un usuario
const { data, error } = await supabase
.from('users')
.insert([
{ email: '[email protected]', name: 'John Doe' }
]);
if (error) {
console.error('Inserción fallida:', error.message);
} else {
console.log('Inserción correcta:', data);
}
Consultar datos:
// Consultar proyectos e incluir datos del usuario
const { data, error } = await supabase
.from('projects')
.select(`
*,
users (
name,
email
)
`)
.eq('status', 'active')
.order('created_at', { ascending: false });
console.log(data);
Una sola consulta trae projects y el usuario relacionado por la clave foránea. En Firestore harían falta varias consultas y unir datos a mano.
Actualizar datos:
const { data, error } = await supabase
.from('projects')
.update({ status: 'completed' })
.eq('id', 1);
Eliminar datos:
const { data, error } = await supabase
.from('projects')
.delete()
.eq('id', 1);
Son operaciones directas. .eq() filtra «igual a»; también hay .gt(), .lt(), .like() — filtros SQL habituales.
Row Level Security (RLS)
Importante cuando trabajas con datos de usuarios.
RLS, Row Level Security: controlas que cada usuario solo vea lo suyo.
Ejemplo: en projects quieres que tras el login solo aparezcan los proyectos del usuario actual.
Activa RLS:
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
Crea una política:
-- El usuario solo ve sus proyectos
CREATE POLICY "Users can view their own projects"
ON projects FOR SELECT
USING (user_id = auth.uid());
auth.uid() devuelve el ID del usuario autenticado. La política limita las filas visibles a las que coinciden con ese ID.
Políticas de inserción, actualización y borrado:
-- Solo insertar proyectos propios
CREATE POLICY "Users can insert their own projects"
ON projects FOR INSERT
WITH CHECK (user_id = auth.uid());
-- Solo actualizar proyectos propios
CREATE POLICY "Users can update their own projects"
ON projects FOR UPDATE
USING (user_id = auth.uid())
WITH CHECK (user_id = auth.uid());
-- Solo eliminar proyectos propios
CREATE POLICY "Users can delete their own projects"
ON projects FOR DELETE
USING (user_id = auth.uid());
Aunque alguien intente consultar datos ajenos, la base los bloquea — más seguro que comprobar solo en el frontend.
Auth: sistema de autenticación
Supabase Auth cubre muchos métodos: email/contraseña, Magic Link sin contraseña, OTP, login social (Google, GitHub, Apple y más de 20 plataformas), teléfono y SSO empresarial.
Panorama de Auth
Mecanismo central: JWT (JSON Web Token). Tras el login, Supabase emite un token; el frontend lo envía en las peticiones y el backend valida la identidad.
Los usuarios se guardan en auth.users de PostgreSQL — tabla automática, sin que la crees tú. ID, email, fechas de creación y último acceso, etc.
También hay persistencia de sesión: el navegador recuerda el login y no hace falta volver a autenticarse en cada visita. El SDK frontend de Supabase lo gestiona solo.
Autenticación Email/Password
Registro:
// Registro de usuario
const { data, error } = await supabase.auth.signUp({
email: '[email protected]',
password: 'securepassword123',
});
if (error) {
console.error('Registro fallido:', error.message);
} else {
console.log('Registro correcto:', data);
}
Tras registrarse, Supabase envía un correo de confirmación; al pulsar el enlace se activa la cuenta. Puedes desactivarlo en el Dashboard, pero confirmar el email reduce registros abusivos.
Inicio de sesión:
// Inicio de sesión
const { data, error } = await supabase.auth.signInWithPassword({
email: '[email protected]',
password: 'securepassword123',
});
if (error) {
console.error('Inicio de sesión fallido:', error.message);
} else {
console.log('Inicio de sesión correcto:', data);
}
Usuario actual:
// Usuario autenticado
const { data: { user } } = await supabase.auth.getUser();
console.log('Usuario actual:', user);
// Ejemplo: { id: 'abc123', email: '[email protected]', ... }
Cierre de sesión:
await supabase.auth.signOut();
La sesión se borra y hay que volver a iniciar sesión.
Restablecer contraseña:
// Enviar correo de restablecimiento
const { data, error } = await supabase.auth.resetPasswordForEmail(
'[email protected]'
);
El usuario recibe el enlace y define una contraseña nueva sin lógica extra tuya.
Social Auth
Login con Google o GitHub sin formularios largos mejora la experiencia.
En el Dashboard: Authentication > Providers, activa Google, GitHub, etc.
Pasos típicos:
- Crear OAuth App en Google/GitHub
- Copiar Client ID y Client Secret a Supabase
- Configurar la URL de callback (Redirect URL)
Código frontend:
// Login con Google
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
});
// Login con GitHub
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github',
});
Redirige a la pantalla de autorización; al aceptar, vuelve a tu app ya autenticado.
Parámetros opcionales:
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: 'https://your-app.com/dashboard',
queryParams: {
access_type: 'offline',
prompt: 'consent',
}
}
});
redirectTo es la página tras el login; queryParams son parámetros OAuth extra.
RLS junto con Auth
Con auth.uid() en políticas conectas login y permisos.
Al crear un proyecto quieres asociarlo al usuario actual:
// Crear proyecto vinculado al usuario actual
const { data: { user } } = await supabase.auth.getUser();
const { data, error } = await supabase
.from('projects')
.insert([
{
title: 'New Project',
user_id: user.id // ID desde Auth
}
]);
RLS garantiza:
- Al consultar, solo filas con
user_id = auth.uid() - Al insertar,
user_iddebe serauth.uid() - Igual para actualizar y borrar
Autenticación, datos y permisos quedan alineados.
Storage: almacenamiento de archivos
Supabase Storage es almacenamiento de objetos, parecido a AWS S3 pero más sencillo. Sirve para avatares, imágenes y documentos.
Conceptos de Storage
Dos ideas clave: Bucket y Object.
- Bucket: contenedor, como una carpeta. Puedes tener
avatars,documents, etc. - Object: el archivo concreto, p. ej.
avatar.jpg,report.pdf
Modos de bucket:
- Public: cualquiera accede (imágenes públicas)
- Private: solo con autorización (documentos privados)
Crear un bucket
En el Dashboard, Storage → «New Bucket».
Ejemplo avatars:
- Nombre:
avatars - Public bucket: marcado (avatares suelen ser públicos)
- File size limit: p. ej. 2 MB
Ya puedes subir archivos.
Subir y descargar archivos
Subida:
// Subir avatar
const file = document.getElementById('avatar-input').files[0];
const { data, error } = await supabase.storage
.from('avatars')
.upload('user-id/avatar.jpg', file, {
cacheControl: '3600',
upsert: false
});
if (error) {
console.error('Subida fallida:', error.message);
} else {
console.log('Subida correcta:', data);
}
Detalles:
- Primer argumento de
upload(): ruta'user-id/avatar.jpg' cacheControl: caché en segundos (3600)upsert: si existe,falsefalla;truesobrescribe
Descarga:
// Descargar archivo
const { data, error } = await supabase.storage
.from('avatars')
.download('user-id/avatar.jpg');
if (error) {
console.error('Descarga fallida:', error.message);
} else {
// data es un Blob; conviértelo a URL para mostrarlo
const url = URL.createObjectURL(data);
document.getElementById('avatar-img').src = url;
}
Bucket público — URL directa:
// URL pública
const { data } = supabase.storage
.from('avatars')
.getPublicUrl('user-id/avatar.jpg');
console.log('URL pública:', data.publicUrl);
// Ejemplo: https://your-project.supabase.co/storage/v1/object/public/avatars/user-id/avatar.jpg
Bucket privado — URL firmada temporal:
// URL temporal (válida 1 hora)
const { data, error } = await supabase.storage
.from('documents')
.createSignedUrl('private-file.pdf', 3600);
console.log('URL temporal:', data.signedUrl);
Eliminar:
const { data, error } = await supabase.storage
.from('avatars')
.remove(['user-id/avatar.jpg']);
Control de acceso
Storage también usa políticas RLS.
Ejemplo: solo la carpeta del usuario.
-- Subir solo a la carpeta propia
CREATE POLICY 'Users can upload to their own folder'
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'avatars' AND
(storage.foldername(name))[1] = auth.uid()::text
);
-- Acceder solo a archivos de la carpeta propia
CREATE POLICY 'Users can access their own files'
ON storage.objects FOR SELECT
USING (
bucket_id = 'avatars' AND
(storage.foldername(name))[1] = auth.uid()::text
);
storage.foldername(name) extrae la carpeta del path; [1] es el primer segmento (ID de usuario).
La ruta debe ser user-id/filename; RLS comprueba que user-id coincida con auth.uid().
Caso práctico: app de gestión de tareas
Un ejemplo que une todo.
App sencilla con:
- Registro e inicio de sesión
- Crear y listar tareas
- Subir adjuntos
Diseño de la base de datos
-- Tabla de usuarios (Auth la crea sola)
-- Tabla tasks
CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
user_id UUID REFERENCES auth.users(id) NOT NULL,
title TEXT NOT NULL,
description TEXT,
status TEXT DEFAULT 'pending' CHECK (status IN ('pending', 'completed')),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Activar RLS
ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;
-- Política: solo las tareas propias
CREATE POLICY 'Users can manage their own tasks'
ON tasks FOR ALL
USING (user_id = auth.uid())
WITH CHECK (user_id = auth.uid());
-- Tabla task_attachments
CREATE TABLE task_attachments (
id SERIAL PRIMARY KEY,
task_id INTEGER REFERENCES tasks(id) ON DELETE CASCADE,
file_name TEXT NOT NULL,
file_path TEXT NOT NULL,
file_size INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Activar RLS
ALTER TABLE task_attachments ENABLE ROW LEVEL SECURITY;
-- Política vía la tarea relacionada
CREATE POLICY 'Users can manage attachments of their tasks'
ON task_attachments FOR ALL
USING (
EXISTS (
SELECT 1 FROM tasks
WHERE tasks.id = task_attachments.task_id
AND tasks.user_id = auth.uid()
)
);
En task_attachments el permiso pasa por task_id → tasks.user_id, no por un user_id directo en adjuntos.
Crear bucket de Storage
Bucket privado task-files:
-- En el Dashboard o con SQL
INSERT INTO storage.buckets (name, public)
VALUES ('task-files', false);
-- Subir solo a la carpeta propia
CREATE POLICY 'Users can upload task files'
ON storage.objects FOR INSERT
WITH CHECK (
bucket_id = 'task-files' AND
(storage.foldername(name))[1] = auth.uid()::text
);
CREATE POLICY 'Users can access task files'
ON storage.objects FOR SELECT
USING (
bucket_id = 'task-files' AND
(storage.foldername(name))[1] = auth.uid()::text
);
Código principal
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
'https://your-project.supabase.co',
'your-anon-key'
);
// 1. Registro
async function register(email: string, password: string) {
const { data, error } = await supabase.auth.signUp({
email,
password,
});
if (error) throw error;
return data;
}
// 2. Inicio de sesión
async function login(email: string, password: string) {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) throw error;
return data;
}
// 3. Crear tarea
async function createTask(title: string, description?: string) {
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error('No has iniciado sesión');
const { data, error } = await supabase
.from('tasks')
.insert([
{
title,
description,
user_id: user.id,
}
])
.select();
if (error) throw error;
return data[0];
}
// 4. Listar tareas
async function getTasks() {
const { data, error } = await supabase
.from('tasks')
.select('*')
.order('created_at', { ascending: false });
if (error) throw error;
return data;
}
// 5. Subir adjunto
async function uploadAttachment(taskId: number, file: File) {
const { data: { user } } = await supabase.auth.getUser();
if (!user) throw new Error('No has iniciado sesión');
const filePath = user.id + '/' + taskId + '/' + file.name;
const { data, error } = await supabase.storage
.from('task-files')
.upload(filePath, file);
if (error) throw error;
// Guardar en task_attachments
const { data: attachment, error: dbError } = await supabase
.from('task_attachments')
.insert([
{
task_id: taskId,
file_name: file.name,
file_path: filePath,
file_size: file.size,
}
])
.select();
if (dbError) throw dbError;
return attachment[0];
}
// 6. Obtener adjuntos
async function getTaskAttachments(taskId: number) {
const { data, error } = await supabase
.from('task_attachments')
.select('*')
.eq('task_id', taskId);
if (error) throw error;
// URLs firmadas temporales
const attachmentsWithURLs = data.map(async (attachment) => {
const { data: urlData } = await supabase.storage
.from('task-files')
.createSignedUrl(attachment.file_path, 3600);
return {
...attachment,
url: urlData.signedUrl,
};
});
return Promise.all(attachmentsWithURLs);
}
// 7. Completar tarea
async function completeTask(taskId: number) {
const { data, error } = await supabase
.from('tasks')
.update({ status: 'completed', updated_at: new Date() })
.eq('id', taskId)
.select();
if (error) throw error;
return data[0];
}
// 8. Cerrar sesión
async function logout() {
await supabase.auth.signOut();
}
Registro, login, CRUD de tareas y archivos — el esqueleto de una app completa. Sobre esto puedes añadir categorías, etiquetas, comentarios o notificaciones.
Supabase vs Firebase
¿Cuál elegir? Comparación directa.
Diferencias principales
| Aspecto | Supabase | Firebase |
|---|---|---|
| Tipo de base de datos | PostgreSQL (relacional) | Firestore (NoSQL documental) |
| Open source | Totalmente open source | Producto cerrado de Google |
| Modelo de precios | Fijo 25 $/mes (Pro Plan) | Por uso (lectura/escritura/almacenamiento) |
| Propiedad de datos | 100 % tuyos, exportación libre | Datos en Google, exportación difícil |
| Consultas | SQL potente y relaciones complejas | Consultas limitadas, joins costosos |
| Tiempo real | WebSocket, suscripción manual | Tiempo real nativo en Firestore |
| Offline | Caché por tu cuenta | Soporte offline nativo |
| Migración | PostgreSQL estándar, sencilla | Formato propietario, coste alto |
Cuándo usar cada uno
Elige Supabase si:
- Relaciones complejas y SQL
- Proyecto a largo plazo y datos bajo control
- El equipo domina SQL y PostgreSQL
- Presupuesto ajustado (coste fijo más predecible)
- Prioridad open source
Elige Firebase si:
- Prototipo rápido con poco tiempo
- App móvil con offline crítico
- Sincronización en tiempo real central (chat, etc.)
- Ya usas Google Cloud
- Datos simples y pocas consultas complejas
En proyectos anteriores con Firebase la factura llegó a más de 800 $/mes; con Supabase, misma funcionalidad, unos 25 $ estables. La diferencia es grande.
Exportar de Firestore es incómodo — formato propietario y conversión extra. Con Supabase exportas SQL o CSV con herramientas PostgreSQL.
Firebase sigue fuerte en tiempo real y móvil: sync y offline de Firestore están muy pulidos. Para chat o documentos colaborativos puede ser más cómodo.
Resumen y recomendaciones
Valor central de Supabase:
- PostgreSQL — consultas potentes y relaciones claras
- Auth de nivel empresarial — varios métodos de login, JWT, RLS
- Almacenamiento de objetos — simple y con control de acceso
- Realtime y Edge Functions — para explorar después
Es open source, datos controlables y coste estable — importante en proyectos largos.
Si eres frontend y quieres full stack sin pelearte con la configuración del backend, Supabase encaja bien: en unas horas puedes tener base de datos, auth y storage — mucho más rápido que un backend clásico.
Recomendaciones de aprendizaje:
- Domina primero Database, Auth y Storage
- Prueba políticas RLS para ver cómo encajan auth y permisos
- Aprende con un proyecto real de principio a fin
- Después explora Realtime, Edge Functions y Vector Database
La documentación oficial está clara: supabase.com/docs. En la comunidad hay tutoriales y listas como awesome-supabase en GitHub.
En una frase: si quieres PostgreSQL como backend sin montar toda la infraestructura, Supabase ya te ha abierto el camino — solo tienes que avanzar.
Primeros pasos con las tres funciones principales de Supabase
Crea un proyecto Supabase desde cero y domina Database, Auth y Storage
⏱️ Estimated time: 2 hr
- 1
Step 1: Crear un proyecto Supabase
Ve a supabase.com, regístrate y crea un proyecto nuevo:
• Nombre del proyecto: my-first-app
• Contraseña de la base de datos: anótala bien
• Región: la más cercana (desde China, Singapore o Tokyo)
Al terminar, obtén Project URL y Anon Public Key en Settings > API - 2
Step 2: Instalar e inicializar el cliente
Instala la dependencia en tu proyecto frontend:
npm install @supabase/supabase-js
Inicializa el cliente Supabase:
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
'https://your-project.supabase.co',
'your-anon-key'
); - 3
Step 3: Crear tablas y configurar RLS
Usa SQL Editor para crear tablas:
CREATE TABLE tasks (
id SERIAL PRIMARY KEY,
user_id UUID REFERENCES auth.users(id),
title TEXT NOT NULL,
status TEXT DEFAULT 'pending'
);
ALTER TABLE tasks ENABLE ROW LEVEL SECURITY;
CREATE POLICY 'Users can manage their own tasks'
ON tasks FOR ALL
USING (user_id = auth.uid());
La política RLS garantiza que cada usuario solo acceda a sus propios datos - 4
Step 4: Implementar autenticación de usuarios
Ejemplos de autenticación Email/Password:
// Registro
await supabase.auth.signUp({
email: '[email protected]',
password: 'password123'
});
// Inicio de sesión
await supabase.auth.signInWithPassword({
email: '[email protected]',
password: 'password123'
});
// Obtener usuario actual
const { data: { user } } = await supabase.auth.getUser();
Soporta inicio de sesión social con Google, GitHub y más de 20 plataformas - 5
Step 5: Configurar almacenamiento de archivos
Crea un bucket de Storage (público o privado):
// Subir archivo
await supabase.storage
.from('avatars')
.upload('user-id/avatar.jpg', file);
// Obtener URL pública
const { data } = supabase.storage
.from('avatars')
.getPublicUrl('user-id/avatar.jpg');
Los archivos privados usan createSignedUrl para generar enlaces temporales
FAQ
¿Cuáles son las diferencias principales entre Supabase y Firebase?
¿Para qué tipo de proyectos encaja Supabase?
• Relaciones de datos complejas que requieren SQL y joins
• Proyectos a largo plazo con datos bajo tu control
• Presupuesto ajustado (coste fijo más predecible)
• Desarrolladores frontend que quieren apps full stack rápido
• Prioridad open source y stack tecnológico controlable
¿Qué es Row Level Security (RLS) y para qué sirve?
¿Qué métodos de inicio de sesión soporta Supabase Auth?
• Email/Password (correo y contraseña)
• Magic Link (sin contraseña)
• OTP (contraseña de un solo uso)
• Social Auth (Google, GitHub, Apple y más de 20 plataformas)
• Phone Auth (Twilio, MessageBird)
• SSO (inicio de sesión único empresarial)
¿Qué diferencia hay entre buckets públicos y privados en Supabase Storage?
¿Cuánto tarda migrar de Firebase a Supabase?
¿Qué incluye el plan gratuito de Supabase?
15 min de lectura · Publicado el: 3 abr 2026 · Actualizado el: 21 ago 2026
Supabase en práctica
Estás leyendo el primer artículo de esta serie. Continúa con el siguiente o abre el hub para ver toda la ruta.
Anterior
Estás al inicio de esta serie.
Siguiente
Diseño de bases de datos en Supabase: tablas, relaciones y Row Level Security
Guía práctica de diseño de bases de datos en Supabase: convenciones de nombres, tres patrones de relaciones, estrategias de Row Level Security y optimización de rendimiento, con casos reales
Parte 2 de 10



Comentarios
Inicia sesión con GitHub para dejar un comentario