O Supabase é a alternativa open-source ao Firebase — banco PostgreSQL, autenticação, storage e real-time. É o backend mais popular entre vibecoders.
O que o Supabase oferece
- PostgreSQL — Banco relacional completo
- Auth — Login com Google, GitHub, email/senha, magic link
- Storage — Upload de arquivos e imagens
- Real-time — Subscriptions via WebSocket
- Edge Functions — Serverless functions (Deno)
- Dashboard visual — Gerenciar tudo pelo navegador
Setup rápido
1. Criar projeto no Supabase
- Acesse supabase.com e crie uma conta
- Clique em New Project
- Escolha um nome e senha para o banco
- Região: escolha a mais próxima do Brasil
2. Pegar as credenciais
No dashboard do Supabase, vá em Settings → API:
- Project URL:
https://xxxx.supabase.co - Anon Key:
eyJ...(pública, usada no client) - Service Role Key:
eyJ...(secreta, usada no server)
3. Configurar na Veloz
# Variáveis públicas (acessíveis no frontend)
veloz env set NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
veloz env set NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
# Variável secreta (apenas no servidor)
veloz env set SUPABASE_SERVICE_KEY=eyJ...Para Vite:
veloz env set VITE_SUPABASE_URL=https://xxxx.supabase.co
veloz env set VITE_SUPABASE_ANON_KEY=eyJ...Next.js + Supabase
Instalar
npm install @supabase/supabase-js @supabase/ssrClient (browser)
// lib/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr";
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
);
}Server (Server Components, API Routes)
// lib/supabase/server.ts
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
export async function createClient() {
const cookieStore = await cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll();
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options));
},
},
},
);
}Exemplo: listar dados
// app/posts/page.tsx
import { createClient } from "@/lib/supabase/server"
export default async function Posts() {
const supabase = await createClient()
const { data: posts } = await supabase
.from("posts")
.select("*")
.order("created_at", { ascending: false })
return (
<ul>
{posts?.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}Autenticação
Login com Google
No Supabase Dashboard: Authentication → Providers → Google e configure o OAuth.
// app/login/page.tsx
"use client"
import { createClient } from "@/lib/supabase/client"
export default function Login() {
const supabase = createClient()
async function signInWithGoogle() {
await supabase.auth.signInWithOAuth({
provider: "google",
options: {
redirectTo: `${window.location.origin}/auth/callback`,
},
})
}
return <button onClick={signInWithGoogle}>Login com Google</button>
}Callback route
// app/auth/callback/route.ts
import { createClient } from "@/lib/supabase/server";
import { NextResponse } from "next/server";
export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const code = searchParams.get("code");
if (code) {
const supabase = await createClient();
await supabase.auth.exchangeCodeForSession(code);
}
return NextResponse.redirect(new URL("/dashboard", request.url));
}Storage (upload de arquivos)
const supabase = createClient();
// Upload
const { data, error } = await supabase.storage.from("avatars").upload(`${userId}/avatar.png`, file);
// URL pública
const {
data: { publicUrl },
} = supabase.storage.from("avatars").getPublicUrl(`${userId}/avatar.png`);Real-time
"use client"
import { useEffect, useState } from "react"
import { createClient } from "@/lib/supabase/client"
export default function Chat() {
const [messages, setMessages] = useState([])
const supabase = createClient()
useEffect(() => {
const channel = supabase
.channel("chat")
.on("postgres_changes", {
event: "INSERT",
schema: "public",
table: "messages",
}, (payload) => {
setMessages((prev) => [...prev, payload.new])
})
.subscribe()
return () => { supabase.removeChannel(channel) }
}, [])
return (
<ul>
{messages.map((msg) => (
<li key={msg.id}>{msg.content}</li>
))}
</ul>
)
}Row Level Security (RLS)
O Supabase usa RLS para proteger dados. No SQL Editor do dashboard:
-- Apenas o dono pode ver seus dados
CREATE POLICY "Users can view own data"
ON posts FOR SELECT
USING (auth.uid() = user_id);
-- Apenas o dono pode inserir
CREATE POLICY "Users can insert own data"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);Deploy
Após configurar tudo:
veloz deployAs variáveis de ambiente já estão configuradas na Veloz — o app conecta ao Supabase automaticamente em produção.
Dica: Migrations
Para manter o schema do banco versionado:
npx supabase init
npx supabase db diff --schema public -f initial
npx supabase db pushPróximos passos
- Deploy com Neon — Alternativa: PostgreSQL puro sem extras
- Full-Stack App — Arquitetura completa
- Variáveis de Ambiente — Gerenciar secrets