CLI para gerenciar branches no Neon
Ferramenta de linha de comando em Node.js que automatiza o ciclo de vida de branches de banco no Neon: criar preview, copiar prod para dev, listar, dropar.
- Node.js 22
- TypeScript
- Commander
- Neon HTTP API
- Zod

Antes desse CLI, cada vez que eu queria testar uma migration localmente eu abria o painel do Neon, clicava em "Create branch", copiava o connection string, colava no .env.local. Em 5 cliques. Para 10 migrations por semana, isso é meia hora perdida. Automatizei.
Comandos disponíveis
1Usage: neon-branch [options] [command]23Gerencia branches de banco no Neon via HTTP API.45Options:6 -V, --version output the version number7 --api-key <key> Neon API key (default: process.env.NEON_API_KEY)8 --project-id <id> Neon project ID (default: process.env.NEON_PROJECT_ID)9 -h, --help display help for command1011Commands:12 list Lista todas as branches do projeto13 create <name> Cria uma branch nova a partir de prod14 copy <from> <to> Copia uma branch existente15 drop <name> Apaga uma branch (com confirmação)16 url <name> Imprime a connection string da branch17 reset <name> Drop + recriar a branch (wipe state)
Por que Zod para validação
A API do Neon retorna JSONs grandes com nomenclatura em snake_case. Zod me dá type-safety no boundary do que vem de fora:
1import { z } from 'zod'23export const BranchSchema = z.object({4 id: z.string().uuid(),5 name: z.string(),6 protected: z.boolean(),7 created_at: z.string().datetime(),8 updated_at: z.string().datetime(),9 // parent_id é null para branches raiz10 parent_id: z.string().uuid().nullable(),11 // ...12})1314export type Branch = z.infer<typeof BranchSchema>1516export async function listBranches(apiKey: string, projectId: string): Promise<Branch[]> {17 const res = await fetch(`https://console.neon.tech/api/v2/projects/${projectId}/branches`, {18 headers: { Authorization: `Bearer ${apiKey}` },19 })2021 if (!res.ok) {22 throw new Error(`Neon API error: ${res.status} ${res.statusText}`)23 }2425 const json = await res.json()26 // Valida na borda — o que entra no resto do código é Branch tipado27 return z.array(BranchSchema).parse(json.branches)28}
O comando "reset" é o que mais uso: pnpm neon-branch reset dev — apaga minha branch dev, recria a partir de prod, e imprime a nova connection string. Em 3 segundos, sem sair do terminal.