guias
Integrações

Veloz + Supabase

Como usar Supabase como backend do seu app na Veloz.

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

  1. Acesse supabase.com e crie uma conta
  2. Clique em New Project
  3. Escolha um nome e senha para o banco
  4. 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/ssr

Client (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 deploy

As 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 push

Próximos passos