Capítulo 07 de 35

Seeds: Como Fazer o Banco de Dados Nascer Vivo

Índice do Manual

Você acabou de rodar supabase db reset. O banco local renasce limpo, todas as tabelas criadas pelas suas Migrations estão lá — mas vazias. Para testar qualquer tela do sistema, você precisa abrir o painel, cadastrar categorias, criar um plano, inventar um usuário admin... tudo na mão. Toda vez.

O Seed resolve esse problema de uma vez por todas. Ele é um arquivo SQL que o Supabase CLI executa automaticamente após todas as Migrations, populando o banco com dados iniciais prontos para uso.


Como o Seed Funciona na Prática

O arquivo vive em um caminho fixo dentro do seu projeto:

supabase/seed.sql

A cadeia de execução é automática e previsível:

supabase db reset

Quando você roda esse comando, o Supabase CLI executa três passos em sequência:

  1. Destrói o banco local atual.
  2. Recria todas as tabelas rodando suas Migrations na ordem cronológica.
  3. Popula o banco executando o seed.sql no final.

Ou seja: toda vez que o banco é recriado, ele já nasce com vida. Zero trabalho manual.


O Que Colocar no Seed (e o Que NÃO Colocar)

O Seed é uma ferramenta de produtividade do desenvolvedor, não um dump de produção. Trate-o como o "kit de sobrevivência" do seu ambiente local.

Colocar:

  • Dados estruturais obrigatórios: categorias, tipos de plano, roles de acesso, listas fixas (estados, países).
  • Um usuário admin de teste com credenciais conhecidas (ex: admin@teste.com / 123456).
  • Dados falsos suficientes para testar as telas principais — de 3 a 5 registros por tabela bastam.

NÃO colocar:

  • Dados de produção reais (CPFs, e-mails de clientes verdadeiros, tokens de API).
  • Milhares de linhas. O seed deve ser rápido, não um dump de 500MB.
  • Lógica condicional complexa. Mantenha SQL puro e simples.

[!TIP] E os geradores automáticos (Faker.js / Snaplet)? Para sistemas iniciais, um seed.sql escrito na mão (focado no essencial) dá menos trabalho de manutenção. Mas quando a empresa cresce e o time precisa de um banco local abarrotado com milhões de registros aleatórios realistas (CPFs, nomes) para testar performance de paginação, a geração procedural através de bibliotecas como Faker.js ou ferramentas como o Snaplet (parceiro oficial do Supabase) torna-se obrigatória para construir seus seeds.


Exemplo Prático

-- =============================================
-- SEED: Dados iniciais para desenvolvimento
-- =============================================

-- Camada 1: Tabelas Raiz (sem dependências)
-- -------------------------------------------

INSERT INTO public.plans (id, name, price, features)
VALUES
  ('free',       'Free',       0,     '{"limits": "basic"}'),
  ('pro',        'Pro',        4990,  '{"limits": "advanced"}'),
  ('enterprise', 'Enterprise', 19990, '{"limits": "unlimited"}')
ON CONFLICT (id) DO NOTHING;

INSERT INTO public.categories (slug, label)
VALUES
  ('tecnologia',  'Tecnologia'),
  ('financeiro',  'Financeiro'),
  ('saude',       'Saúde'),
  ('educacao',    'Educação')
ON CONFLICT (slug) DO NOTHING;


-- Camada 2: Tabelas que dependem da Camada 1
-- -------------------------------------------

INSERT INTO public.organizations (id, name, plan_id)
VALUES
  ('org-teste', 'Empresa de Teste', 'pro')
ON CONFLICT (id) DO NOTHING;


-- Camada 3: Dados de teste para o dia a dia
-- -------------------------------------------

INSERT INTO public.projects (
  id, title, category_slug, organization_id
)
VALUES
  ('proj-1', 'Projeto Alpha', 'tecnologia', 'org-teste'),
  ('proj-2', 'Projeto Beta',  'financeiro', 'org-teste'),
  ('proj-3', 'Projeto Gamma', 'saude',      'org-teste')
ON CONFLICT (id) DO NOTHING;

O segredo desse arquivo está na cláusula ON CONFLICT DO NOTHING. Ela torna o seed idempotente: você pode executá-lo uma, duas ou cem vezes sem nunca gerar erro de duplicação. Se o registro já existe, o Postgres simplesmente ignora a linha.


O Cuidado com Foreign Keys: Ordem de Inserção

Seeds devem respeitar a hierarquia de dependências do seu banco. Se a tabela organizations possui uma Foreign Key apontando para plans, você precisa inserir os planos antes das organizações.

A boa prática é organizar o seu seed.sql em camadas numeradas:

  • Camada 1: Tabelas raiz (sem FK para nenhuma outra tabela).
  • Camada 2: Tabelas que dependem da Camada 1.
  • Camada 3: Tabelas que dependem da Camada 2.

Se você inverter a ordem, o Postgres vai rejeitar o INSERT com um erro de violação de Foreign Key e o db reset vai falhar.


A Trava de Segurança: Nunca Rodar Seed em Produção

O comando supabase db reset é uma operação destrutiva que apaga todo o banco antes de recriá-lo. Por isso, o Supabase CLI já bloqueia esse comando quando o projeto está linkado a um banco remoto de produção.

Mesmo assim, reforce essa regra na sua equipe: o Seed é uma ferramenta exclusivamente local e de staging.

Se você precisa de dados que devem existir obrigatoriamente em produção (como uma lista fixa de estados brasileiros ou os planos iniciais do SaaS), o caminho correto é criar uma Migration dedicada com esses INSERTs — não o seed.


Seed vs Migration de Dados: Quando Usar Cada Um

Cenário Ferramenta Por quê?
Dados de teste para o dev local Seed Dados descartáveis, morrem no db reset
Dados obrigatórios em produção (ex: lista de estados) Migration Precisam existir em todos os ambientes
Popular uma tabela logo após criá-la Migration Rode o INSERT na mesma Migration do CREATE
Dados falsos para demonstrar ao cliente em staging Seed Ambiente de homologação é descartável
Usuário admin padrão para login local Seed Credenciais de teste não vão para produção

A partir de agora, toda vez que o seu banco local for destruído e recriado, ele já nasce equipado com planos, categorias, organizações e projetos de teste. Seu time de desenvolvimento nunca mais vai perder tempo cadastrando dados na mão para poder trabalhar.

Com o banco estruturado (Migrations) e populado (Seeds), está na hora de dar inteligência e lógica serverless a ele. Siga para o próximo manual: Supabase Edge Functions: Criação, Testes e Deploy.