Communitygithub.com

padrões-de-migração-de-banco-de-dados

Melhores práticas para migrações de banco de dados: alterações de esquema, migrações de dados, rollbacks e implantações com zero downtime para PostgreSQL, MySQL e ORMs comuns (Prisma, Drizzle, Kysely, Django, TypeORM, golang-migrate). Use ao criar uma migração de esquema ou dados, planejar um rollback ou buscar uma implantação sem tempo de inatividade.

O que é padrões-de-migração-de-banco-de-dados?

Este skill fornece um guia completo e prático sobre padrões de migração de banco de dados, com foco em segurança, reversibilidade e mínimo impacto em produção. Ele abrange princípios fundamentais (como migrações imutáveis e separação entre esquema e dados), um checklist de segurança, e padrões específicos para PostgreSQL (adição/remoção de colunas, índices concorrentes, migrações em lote) e os ORMs mais populares do ecossistema: Prisma, Drizzle, Kysely, Django e golang-migrate. O conteúdo inclui exemplos de código executáveis, comandos CLI, fluxos de trabalho (expand-contract para zero downtime) e uma tabela de anti-padrões com alternativas recomendadas. É ideal para desenvolvedores e engenheiros de dados que precisam planejar e executar alterações evolutivas e seguras em bancos de dados relacionais, especialmente PostgreSQL.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/database-migrations

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Padrões de Migração de Banco de Dados

Alterações seguras e reversíveis no esquema do banco de dados para sistemas em produção.

Quando Ativar

  • Criar ou alterar tabelas do banco de dados
  • Adicionar/remover colunas ou índices
  • Executar migrações de dados (preenchimento retroativo, transformação)
  • Planejar alterações de esquema sem tempo de inatividade
  • Configurar ferramentas de migração para um novo projeto

Princípios Fundamentais

  1. Toda alteração é uma migração — nunca altere bancos de dados de produção manualmente
  2. Migrações são apenas para frente em produção — rollbacks usam novas migrações para frente
  3. Migrações de esquema e dados são separadas — nunca misture DDL e DML em uma única migração
  4. Teste migrações com dados do tamanho da produção — uma migração que funciona em 100 linhas pode travar em 10 milhões
  5. Migrações são imutáveis após implantadas — nunca edite uma migração que já foi executada em produção

Checklist de Segurança de Migração

Antes de aplicar qualquer migração:

  • A migração tem tanto UP quanto DOWN (ou é explicitamente marcada como irreversível)
  • Sem bloqueios de tabela completa em tabelas grandes (use operações concorrentes)
  • Novas colunas têm valores padrão ou são anuláveis (nunca adicione NOT NULL sem padrão)
  • Índices criados concorrentemente (não inline com CREATE TABLE para tabelas existentes)
  • O preenchimento retroativo de dados é uma migração separada da alteração de esquema
  • Testado contra uma cópia dos dados de produção
  • Plano de rollback documentado

Padrões PostgreSQL

Adicionar uma Coluna com Segurança

-- BOM: Coluna anulável, sem bloqueio
ALTER TABLE users ADD COLUMN avatar_url TEXT;

-- BOM: Coluna com valor padrão (Postgres 11+ é instantâneo, sem reescrita)
ALTER TABLE users ADD COLUMN is_active BOOLEAN NOT NULL DEFAULT true;

-- RUIM: NOT NULL sem padrão em tabela existente (requer reescrita completa)
ALTER TABLE users ADD COLUMN role TEXT NOT NULL;
-- Isso bloqueia a tabela e reescreve todas as linhas

Adicionar um Índice Sem Tempo de Inatividade

-- RUIM: Bloqueia escritas em tabelas grandes
CREATE INDEX idx_users_email ON users (email);

-- BOM: Sem bloqueio, permite escritas concorrentes
CREATE INDEX CONCURRENTLY idx_users_email ON users (email);

-- Nota: CONCURRENTLY não pode ser executado dentro de um bloco de transação
-- A maioria das ferramentas de migração precisa de tratamento especial para isso

Renomear uma Coluna (Zero Downtime)

Nunca renomeie diretamente em produção. Use o padrão expandir-contrair:

-- Passo 1: Adicionar nova coluna (migração 001)
ALTER TABLE users ADD COLUMN display_name TEXT;

-- Passo 2: Preencher dados retroativamente (migração 002, migração de dados)
UPDATE users SET display_name = username WHERE display_name IS NULL;

-- Passo 3: Atualizar o código da aplicação para ler/escrever ambas as colunas
-- Implantar alterações na aplicação

-- Passo 4: Parar de escrever na coluna antiga, removê-la (migração 003)
ALTER TABLE users DROP COLUMN username;

Remover uma Coluna com Segurança

-- Passo 1: Remover todas as referências à coluna na aplicação
-- Passo 2: Implantar a aplicação sem a referência à coluna
-- Passo 3: Remover a coluna na próxima migração
ALTER TABLE orders DROP COLUMN legacy_status;

-- Para Django: use SeparateDatabaseAndState para remover do modelo
-- sem gerar DROP COLUMN (depois remova na próxima migração)

Migrações de Dados Grandes

-- RUIM: Atualiza todas as linhas em uma transação (bloqueia a tabela)
UPDATE users SET normalized_email = LOWER(email);

-- BOM: Atualização em lote com progresso
DO $$
DECLARE
  batch_size INT := 10000;
  rows_updated INT;
BEGIN
  LOOP
    UPDATE users
    SET normalized_email = LOWER(email)
    WHERE id IN (
      SELECT id FROM users
      WHERE normalized_email IS NULL
      LIMIT batch_size
      FOR UPDATE SKIP LOCKED
    );
    GET DIAGNOSTICS rows_updated = ROW_COUNT;
    RAISE NOTICE 'Updated % rows', rows_updated;
    EXIT WHEN rows_updated = 0;
    COMMIT;
  END LOOP;
END $$;

Prisma (TypeScript/Node.js)

Fluxo de Trabalho

# Criar migração a partir das alterações no esquema
npx prisma migrate dev --name add_user_avatar

# Aplicar migrações pendentes em produção
npx prisma migrate deploy

# Redefinir banco de dados (apenas dev)
npx prisma migrate reset

# Gerar cliente após alterações no esquema
npx prisma generate

Exemplo de Esquema

model User {
  id        String   @id @default(cuid())
  email     String   @unique
  name      String?
  avatarUrl String?  @map("avatar_url")
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")
  orders    Order[]

  @@map("users")
  @@index([email])
}

Migração SQL Personalizada

Para operações que o Prisma não pode expressar (índices concorrentes, preenchimento retroativo de dados):

# Criar migração vazia, depois editar o SQL manualmente
npx prisma migrate dev --create-only --name add_email_index
-- migrations/20240115_add_email_index/migration.sql
-- Prisma não pode gerar CONCURRENTLY, então escrevemos manualmente
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_users_email ON users (email);

Drizzle (TypeScript/Node.js)

Fluxo de Trabalho

# Gerar migração a partir das alterações no esquema
npx drizzle-kit generate

# Aplicar migrações
npx drizzle-kit migrate

# Enviar esquema diretamente (apenas dev, sem arquivo de migração)
npx drizzle-kit push

Exemplo de Esquema

import { pgTable, text, timestamp, uuid, boolean } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: uuid("id").primaryKey().defaultRandom(),
  email: text("email").notNull().unique(),
  name: text("name"),
  isActive: boolean("is_active").notNull().default(true),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

Kysely (TypeScript/Node.js)

Fluxo de Trabalho (kysely-ctl)

# Inicializar arquivo de configuração (kysely.config.ts)
kysely init

# Criar um novo arquivo de migração
kysely migrate make add_user_avatar

# Aplicar todas as migrações pendentes
kysely migrate latest

# Reverter a última migração
kysely migrate down

# Mostrar status das migrações
kysely migrate list

Arquivo de Migração

// migrations/2024_01_15_001_create_user_profile.ts
import { type Kysely, sql } from 'kysely'

// IMPORTANTE: Sempre use Kysely<any>, não sua interface DB tipada.
// As migrações são congeladas no tempo e não devem depender dos tipos de esquema atuais.
export async function up(db: Kysely<any>): Promise<void> {
  await db.schema
    .createTable('user_profile')
    .addColumn('id', 'serial', (col) => col.primaryKey())
    .addColumn('email', 'varchar(255)', (col) => col.notNull().unique())
    .addColumn('avatar_url', 'text')
    .addColumn('created_at', 'timestamp', (col) =>
      col.defaultTo(sql`now()`).notNull()
    )
    .execute()

  await db.schema
    .createIndex('idx_user_profile_avatar')
    .on('user_profile')
    .column('avatar_url')
    .execute()
}

export async function down(db: Kysely<any>): Promise<void> {
  await db.schema.dropTable('user_profile').execute()
}

Migrador Programático

import { Migrator, FileMigrationProvider } from 'kysely'
import { promises as fs } from 'fs'
import * as path from 'path'
// ESM apenas — CJS pode usar __dirname diretamente
import { fileURLToPath } from 'url'
const migrationFolder = path.join(
  path.dirname(fileURLToPath(import.meta.url)),
  './migrations',
)

// `db` é sua instância de banco de dados Kysely<any>
const migrator = new Migrator({
  db,
  provider: new FileMigrationProvider({
    fs,
    path,
    migrationFolder,
  }),
  // AVISO: Ative apenas em desenvolvimento. Desativa a validação
  // de ordenação por timestamp, o que pode causar desvios de esquema entre ambientes.
  // allowUnorderedMigrations: true,
})

const { error, results } = await migrator.migrateToLatest()

results?.forEach((it) => {
  if (it.status === 'Success') {
    console.log(`migration "${it.migrationName}" executed successfully`)
  } else if (it.status === 'Error') {
    console.error(`failed to execute migration "${it.migrationName}"`)
  }
})

if (error) {
  console.error('migration failed', error)
  process.exit(1)
}

Django (Python)

Fluxo de Trabalho

# Gerar migração a partir das alterações no modelo
python manage.py makemigrations

# Aplicar migrações
python manage.py migrate

# Mostrar status das migrações
python manage.py showmigrations

# Gerar migração vazia para SQL personalizado
python manage.py makemigrations --empty app_name -n description

Migração de Dados

from django.db import migrations

def backfill_display_names(apps, schema_editor):
    User = apps.get_model("accounts", "User")
    batch_size = 5000
    users = User.objects.filter(display_name="")
    while users.exists():
        batch = list(users[:batch_size])
        for user in batch:
            user.display_name = user.username
        User.objects.bulk_update(batch, ["display_name"], batch_size=batch_size)

def reverse_backfill(apps, schema_editor):
    pass  # Migração de dados, nenhum reverso necessário

class Migration(migrations.Migration):
    dependencies = [("accounts", "0015_add_display_name")]

    operations = [
        migrations.RunPython(backfill_display_names, reverse_backfill),
    ]

SeparateDatabaseAndState

Remover uma coluna do modelo Django sem removê-la imediatamente do banco de dados:

class Migration(migrations.Migration):
    operations = [
        migrations.SeparateDatabaseAndState(
            state_operations=[
                migrations.RemoveField(model_name="user", name="legacy_field"),
            ],
            database_operations=[],  # Não toque no banco ainda
        ),
    ]

golang-migrate (Go)

Fluxo de Trabalho

# Criar par de migração
migrate create -ext sql -dir migrations -seq add_user_avatar

# Aplicar todas as migrações pendentes
migrate -path migrations -database "$DATABASE_URL" up

# Reverter a última migração
migrate -path migrations -database "$DATABASE_URL" down 1

# Forçar versão (corrigir estado sujo)
migrate -path migrations -database "$DATABASE_URL" force VERSION

Arquivos de Migração

-- migrations/000003_add_user_avatar.up.sql
ALTER TABLE users ADD COLUMN avatar_url TEXT;
CREATE INDEX CONCURRENTLY idx_users_avatar ON users (avatar_url) WHERE avatar_url IS NOT NULL;

-- migrations/000003_add_user_avatar.down.sql
DROP INDEX IF EXISTS idx_users_avatar;
ALTER TABLE users DROP COLUMN IF EXISTS avatar_url;

Estratégia de Migração Zero Downtime

Para alterações críticas em produção, siga o padrão expandir-contrair:

Fase 1: EXPANDIR
  - Adicionar nova coluna/tabela (anulável ou com padrão)
  - Implantar: aplicação escreve em AMBAS (antiga e nova)
  - Preencher dados retroativamente existentes

Fase 2: MIGRAR
  - Implantar: aplicação lê da NOVA, escreve em AMBAS
  - Verificar consistência dos dados

Fase 3: CONTRAIR
  - Implantar: aplicação usa apenas a NOVA
  - Remover coluna/tabela antiga em migração separada

Exemplo de Cronograma

Dia 1: Migração adiciona coluna new_status (anulável)
Dia 1: Implantar aplicação v2 — escreve em status e new_status
Dia 2: Executar migração de preenchimento retroativo para linhas existentes
Dia 3: Implantar aplicação v3 — lê apenas de new_status
Dia 7: Migração remove a coluna antiga status

Anti-Padrões

Anti-PadrãoPor que FalhaAbordagem Melhor
SQL manual em produçãoSem trilha de auditoria, não repetívelSempre usar arquivos de migração
Editar migrações já implantadasCausa desvio entre ambientesCriar nova migração em vez disso
NOT NULL sem padrãoBloqueia tabela, reescreve todas as linhasAdicionar anulável, preencher retroativamente, depois adicionar restrição
Índice inline em tabela grandeBloqueia escritas durante a construçãoCREATE INDEX CONCURRENTLY
Esquema + dados em uma migraçãoDifícil reverter, transações longasMigrações separadas
Remover coluna antes de remover códigoErros na aplicação por coluna faltanteRemover código primeiro, remover coluna na próxima implantação

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Habilidades Relacionadas