1

Supabase como Backend Completo para Next.js

O problema que o Supabase resolve (e o que ele não resolve)

Montar um backend para uma aplicação Next.js exige decisões sobre autenticação, banco de dados, storage de arquivos e, dependendo do caso, comunicação em tempo real. A abordagem clássica envolve configurar um PostgreSQL, um serviço de auth (Auth0, Clerk, NextAuth), um S3 para arquivos e um servidor WebSocket separado. São quatro serviços, quatro faturas, quatro pontos de falha.

O Supabase empacota tudo isso em cima de um PostgreSQL real: auth com JWT, storage com políticas de acesso, realtime via WebSockets e uma API REST gerada automaticamente pelo PostgREST. A proposta é eliminar boilerplate de infraestrutura sem abrir mão do controle que um banco relacional oferece.

Onde o Supabase não encaixa: se você precisa de lógica de negócio complexa no backend (filas, workers, orquestração de serviços), ele não substitui um servidor dedicado. Nesses casos, o Supabase funciona como camada de dados e auth, e a lógica fica em API Routes do Next.js ou em um serviço separado.

Instalação e configuração inicial

Crie um projeto no dashboard do Supabase e copie a SUPABASE_URL e a SUPABASE_ANON_KEY. A anon key é pública por design: a segurança vem do Row Level Security, não do sigilo dessa chave.

npm install @supabase/supabase-js @supabase/ssr

Crie o arquivo de variáveis de ambiente:

# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://seuprojetoid.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

O prefixo NEXT_PUBLIC_ expõe essas variáveis no client. Isso é intencional: a anon key só permite operações que as políticas RLS autorizam.

Criando os clientes: server e browser

O @supabase/ssr oferece helpers para criar clientes que gerenciam cookies corretamente no App Router. A separação entre client de servidor e client de browser é obrigatória porque o Next.js executa código nos dois ambientes.

// src/lib/supabase/server.ts
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export async function createSupabaseServer() {
  const cookieStore = await cookies();

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        // getAll/setAll é a API recomendada pelo @supabase/ssr v0.5+
        // evita problemas de sincronização com cookies individuais
        getAll() {
          return cookieStore.getAll();
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) =>
              cookieStore.set(name, value, options)
            );
          } catch {
            // setAll falha em Server Components (read-only)
            // funciona em Server Actions e Route Handlers
          }
        },
      },
    }
  );
}
// src/lib/supabase/browser.ts
import { createBrowserClient } from "@supabase/ssr";

export function createSupabaseBrowser() {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );
}

O middleware renova tokens expirados antes que a request chegue ao Server Component:

// src/middleware.ts
import { createServerClient } from "@supabase/ssr";
import { NextResponse, type NextRequest } from "next/server";

export async function middleware(request: NextRequest) {
  let supabaseResponse = NextResponse.next({ request });

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        getAll() {
          return request.cookies.getAll();
        },
        setAll(cookiesToSet) {
          // Propaga cookies tanto na request quanto na response
          // sem isso, Server Components recebem sessão stale
          cookiesToSet.forEach(

---

Leia o artigo completo em [https://www.vivodecodigo.com.br/nextjs/supabase-backend-completo-nextjs-auth-database-rls-storage](https://www.vivodecodigo.com.br/nextjs/supabase-backend-completo-nextjs-auth-database-rls-storage)
Carregando publicação patrocinada...
1

Cara, excelente para fazer um backend basico essa estratégia. Joga o frontend num gitpages e backend com next já fica pronto.