SLA de p95 < 300ms: Arquitetura Edge Vercel e Supabase Service Role
Atingindo Latência Ultra-baixa em Picos de Acesso (SLA p95 < 300ms)

Quando o negócio exige garantias contratuais de resposta quase instantânea sob um pico brutal de tráfego simultâneo, não basta ter um banco de dados forte. É necessário mitigar três gargalos clássicos do serverless: a distância física (rede), a inicialização fria (cold starts) e a validação em banco (RLS).
Abaixo estão as diretrizes de arquitetura para resolver esse desafio na stack Next.js (Vercel) + Supabase.
1. Colocation (Mitigação de Rede)
O maior inimigo da latência é a distância. Se a Vercel executar sua API Serverless no Brasil e o Supabase estiver na Virgínia (EUA), você perderá de 120ms a 150ms de roundtrip antes mesmo do código rodar.
- Regra de Ouro: O banco de dados (Supabase) e a execução primária da Vercel devem estar na mesma região.
- Configuração Br:
sa-east-1no Supabase egru1na Vercel. Isso reduz a latência da comunicação entre eles para ~5ms.
2. Vercel Edge Runtime (O Fim dos Cold Starts)
Uma função Node.js tradicional (Serverless) da Vercel pode demorar de 800ms a 2.000ms para "acordar" instâncias simultâneas se 10.000 pessoas acessarem a API ao mesmo tempo.
- A Solução: Forçar o uso de V8 Isolates usando
export const runtime = 'edge'. - O Edge Runtime inicializa em menos de 1ms. Ele não suporta algumas APIs nativas do Node.js, mas é perfeito para chamadas HTTP hiper-velozes ao banco.
3. Supabase Service Role (Bypass de RLS)
Avaliar Row Level Security custa ciclos de CPU no banco, porque o PostgreSQL precisa cruzar tabelas temporárias e decodificar tokens em tempo real.
- A Solução de Pico: Em uma API específica que já foi fortemente validada via token na Edge Function da Vercel, conecte-se ao Supabase utilizando a
SERVICE_ROLE_KEY. - Isso insere dados como "Deus" (Admin), bypassando o RLS do banco de dados e economizando entre 10ms a 30ms cruciais.
- ATENÇÃO: Isso só deve ser feito no backend. Nunca exponha essa chave no cliente.
4. Estratégia de Unique Constraint (DB Fail-Fast)
Não use a Vercel para fazer SELECT antes de INSERT tentando verificar se um usuário já votou (isso duplica o tempo e o custo).
Em vez disso, delegue a restrição para o banco de dados criando uma UNIQUE INDEX. Tente fazer o INSERT diretamente; se a regra for quebrada, o banco retorna um código de erro veloz (23505).
Exemplo de Rota Limpa e Veloz
// app/api/action/route.ts
export const runtime = 'edge'; // Força Inicialização em < 1ms
export const preferredRegion = 'gru1'; // Colocation com o Banco
import { createClient } from '@supabase/supabase-js';
import { NextResponse } from 'next/server';
// Instancia fora do handler para aproveitar pool HTTP em memória
const supabaseAdmin = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!, // Bypass de RLS
{
auth: {
persistSession: false, // Desliga overheads do GoTrue
autoRefreshToken: false,
}
}
);
export async function POST(request: Request) {
try {
const data = await request.json();
if (!data.userId || !data.itemId) {
return NextResponse.json({ error: 'Payload inválido' }, { status: 400 });
}
const { error } = await supabaseAdmin
.from('actions')
.insert({ user_id: data.userId, item_id: data.itemId });
if (error) {
if (error.code === '23505') { // Restrição Única (Unique Violation)
return NextResponse.json({ error: 'Ação já realizada' }, { status: 409 });
}
return NextResponse.json({ error: 'Falha interna' }, { status: 500 });
}
return new NextResponse(null, { status: 201 }); // Resposta de 0 bytes = máxima velocidade
} catch (err) {
return NextResponse.json({ error: 'Bad Request' }, { status: 400 });
}
}
5. Pré-aquecimento (Cron Ping)
Cinco minutos antes de eventos de pico agendados, dispare Pings sintéticos (GET vazio ou SELECT 1) na sua rota para manter as conexões TCP do Edge Server com o Supabase PostgREST aquecidas, eliminando o DNS Lookup da primeira requisição do pico.