Instalación y Setup de Supabase

En esta guía vas a crear tu proyecto en Supabase, instalar el SDK en tu app y hacer tu primera query a la base de datos. Todo en menos de 10 minutos.

Crear un proyecto en Supabase

Antes de tocar código, necesitas un proyecto en la plataforma.

  1. Ve a supabase.com y crea una cuenta (puedes usar GitHub para hacerlo más rápido)
  2. En el dashboard, haz clic en New Project
  3. Selecciona la organización (si es tu primera vez, Supabase crea una por defecto)
  4. Completa los datos del proyecto:
    • Name: el nombre de tu proyecto (por ejemplo, mi-app)
    • Database Password: una contraseña fuerte para tu base de datos PostgreSQL. Guárdala en un lugar seguro porque la vas a necesitar si te conectas directo a la base de datos
    • Region: elige la región más cercana a tus usuarios. Para LATAM, South America (Sao Paulo) suele ser la mejor opción
  5. Haz clic en Create new project
Tiempo de creación

Supabase tarda entre 1 y 2 minutos en provisionar tu proyecto. Está creando una instancia completa de PostgreSQL, configurando los servicios de auth, storage y generando tus API keys.

Cuando termine, vas a llegar al dashboard de tu proyecto. Desde ahí puedes ver tus API keys yendo a Settings > API.

Instalar el SDK

El SDK de Supabase es el paquete @supabase/supabase-js. Es la librería que tu app usa para comunicarse con tu proyecto de Supabase.

bash
npm install @supabase/supabase-js

Eso es todo. No hay configuraciones extra ni dependencias adicionales.

Compatibilidad

@supabase/supabase-js funciona en el browser, en Node.js, en Deno y en cualquier runtime de JavaScript. No importa si tu proyecto es NextJS, React, Vue, Svelte o vanilla JS.

Variables de entorno

Supabase necesita dos valores para conectarse: la URL de tu proyecto y una API key. Ambos los encuentras en el dashboard en Settings > API.

Crea un archivo .env.local en la raíz de tu proyecto con estas dos variables:

plaintext
NEXT_PUBLIC_SUPABASE_URL=tu-url-aca
NEXT_PUBLIC_SUPABASE_ANON_KEY=tu-anon-key-aca
Nunca expongas la service_role key en el cliente

En tu código vas a acceder a estos valores como process.env.NEXT_PUBLIC_SUPABASE_URL y process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY. El prefijo NEXT_PUBLIC_ los hace accesibles en el browser, lo cual está bien para la anon key. Nunca hagas esto con la service_role key.

Las dos API keys

Supabase te da dos keys con propósitos diferentes. Entender la diferencia es importante para no armar un agujero de seguridad.

anon key (clave pública)

La anon key es una clave pública. Sí, pública. Está diseñada para usarse en el cliente (browser, app mobile). No es un secreto.

La seguridad no depende de que esta clave sea secreta, sino de las políticas de RLS (Row Level Security -- permisos que defines a nivel de base de datos) que configures en tus tablas. Sin RLS habilitado, la anon key tiene acceso a todo. Con RLS, solo puede hacer lo que tus políticas permitan.

Cuándo usarla: siempre que tu app se comunique con Supabase desde el cliente.

service_role key (clave secreta)

La service_role key es un secreto. Esta clave bypasea completamente el RLS. Tiene acceso total a toda tu base de datos sin restricciones.

Cuándo usarla: solo en el servidor. Server Actions, Route Handlers, scripts de migración, funciones serverless. Nunca en código que corra en el browser.

plaintext
# Esto va en .env.local pero SIN el prefijo NEXT_PUBLIC_
SUPABASE_SERVICE_ROLE_KEY=tu-service-role-key-aca

En tu código del servidor, accedes con process.env.SUPABASE_SERVICE_ROLE_KEY.

Regla de oro

Si tu key tiene el prefijo NEXT_PUBLIC_, es visible para cualquiera que abra DevTools en el browser. La service_role key nunca debe tener ese prefijo.

Configurar el cliente de Supabase

Crea un archivo para inicializar el cliente. La convención es ponerlo en lib/supabase.ts:

typescript
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
 
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
 
export const supabase = createClient(supabaseUrl, supabaseAnonKey)

Este cliente usa la anon key y es seguro para usarse tanto en el servidor como en el cliente. Las operaciones que haga están sujetas a las políticas de RLS que configures.

Cliente para el servidor con service_role

Si necesitas un cliente con acceso total (para operaciones administrativas), crea uno aparte:

typescript
// lib/supabase-admin.ts
import { createClient } from '@supabase/supabase-js'
 
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!
 
export const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey)
Solo en el servidor

Nunca importes supabase-admin.ts en un Client Component. Este archivo solo debe usarse en Server Components, Server Actions o Route Handlers.

Tu primera query

Vamos a verificar que todo funciona. Para este ejemplo, supongamos que tienes una tabla posts en tu base de datos (la puedes crear desde el dashboard en Table Editor > New Table).

typescript
import { supabase } from '@/lib/supabase'
 
async function getPosts() {
  const { data, error } = await supabase
    .from('posts')
    .select('*')
    .order('created_at', { ascending: false })
    .limit(10)
 
  if (error) {
    console.error('Error al obtener posts:', error.message)
    return []
  }
 
  return data
}

Eso es lo que hace el SDK por debajo: convierte tus llamadas en requests HTTP a la API REST auto-generada de Supabase (PostgREST). El .from('posts') apunta a la tabla posts, .select('*') trae todas las columnas, y .order() y .limit() hacen lo que esperarías.

Ejemplo en un Server Component de NextJS

tsx
// app/posts/page.tsx
import { supabase } from '@/lib/supabase'
 
export default async function PostsPage() {
  const { data: posts, error } = await supabase
    .from('posts')
    .select('id, title, created_at')
    .order('created_at', { ascending: false })
 
  if (error) {
    return <p>Error al cargar los posts.</p>
  }
 
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  )
}
Tipado automático

Supabase puede generar tipos de TypeScript basados en tu esquema de base de datos usando el CLI. Esto te da autocompletado en tu editor para nombres de tablas, columnas y tipos de datos. Lo vamos a cubrir más adelante.

Problemas comunes

"Invalid API key"

Revisa que tus variables de entorno estén bien copiadas. No deberían tener espacios extra ni comillas alrededor del valor. Reinicia el servidor de desarrollo después de modificar .env.local.

"relation does not exist"

Estás intentando consultar una tabla que no existe. Verifica el nombre exacto en el Table Editor del dashboard. Los nombres son case-sensitive.

La query devuelve un array vacío

Si la tabla tiene datos pero la query no devuelve nada, probablemente tienes RLS habilitado sin una política que permita la lectura. Ve al dashboard, selecciona tu tabla, y revisa las políticas en la sección RLS Policies.


Resumen

PasoQué hicimos
Crear proyectoDashboard de Supabase > New Project
Instalar SDKnpm install @supabase/supabase-js
Variables de entornoNEXT_PUBLIC_SUPABASE_URL y NEXT_PUBLIC_SUPABASE_ANON_KEY en .env.local
Cliente públicolib/supabase.ts con createClient y la anon key
Cliente adminlib/supabase-admin.ts con createClient y la service_role key (solo servidor)
Primera query.from('tabla').select('*')