Versionar os workflows do n8n no Git

TLDR: Versionar os workflows do n8n como JSONs em snake_case em src/workflows/, com scripts de export (local/staging/prod) e de deploy (todos os workflows ou apenas um).

Contexto

Os workflows do n8n existem apenas no banco PostgreSQL. Nada é versionado no Git, o que impede rastrear mudanças, fazer code review e automatizar deploys reproduzíveis. O objetivo é que src/workflows/ seja a fonte da verdade: o dev exporta localmente, commita, e o deploy importa em staging e em produção a partir dos arquivos.

Fluxo completo

mermaid graph LR A["dev local<br/>make n8n.workflows.export"] --> B["git commit"] B --> C["make n8n.workflows.deploy<br/>(staging via kubectl)"] C --> D["make n8n.promote<br/>(produção via kubectl)"]

Objetivos

  • Exportar os workflows do n8n local como JSONs individuais em snake_case em src/workflows/
  • O deploy lê os JSONs do repo e importa em staging ou produção (substituindo tudo)
  • O promote (staging→prod) passa a importar a partir dos JSONs, não mais do banco de staging
  • Suportar o deploy de um único workflow, por nome de arquivo

Fora de escopo

Workflow desabilitado não é versionado. Um workflow com active: false não deve existir em src/workflows/. O export.sh pula workflows desabilitados e remove qualquer JSON obsoleto de um export anterior, de modo que a árvore versionada contenha só workflows ativos. Workflows desabilitados costumam ser testes, depreciados ou rascunhos — versioná-los só adiciona ruído. Para reativar um, reabilite no n8n e reexporte.

Mudanças

Arquivo Ação
bin/n8n/export.sh criar — exporta workflows para src/workflows/ (local via docker, k8s via kubectl)
bin/n8n/deploy.sh criar — importa todos os JSONs de src/workflows/ em staging ou prod (substitui tudo)
bin/n8n/promote.sh atualizar — passa a chamar deploy.sh production em vez de exportar de staging
Makefile atualizar — adiciona os targets abaixo
src/workflows/.gitkeep criar

bin/n8n/export.sh (novo)

  • Argumento: local (default) | staging | production
  • local: usa docker compose exec n8n n8n export:workflow --all --separate --output=/tmp/n8n-workflows/ e copia para src/workflows/
  • staging/production: usa kubectl exec no pod mkt-n8n-<env> e kubectl cp
  • Renomeia os arquivos para snake_case (minúsculas, espaços/especiais → _, sem underscores duplos)
  • Imprime o aviso de que credenciais não são exportadas

bin/n8n/deploy.sh (novo)

  • Argumento: staging | production
  • Copia todos os JSONs de src/workflows/ para o pod via kubectl cp
  • Executa n8n import:workflow --separate --input=/tmp/n8n-workflows/ no pod (substitui tudo)
  • Aceita WORKFLOW=<snake_case_name> para importar apenas um arquivo

bin/n8n/promote.sh (atualizar)

  • Remove a lógica de export a partir de staging
  • Passa a chamar bash "$(dirname "$0")/deploy.sh" production
  • Mantém o backup de produção antes de importar

Makefile (targets novos)

```makefile ### Export workflows from local n8n to src/workflows/ n8n.workflows.export: @bash bin/n8n/export.sh local

Export workflows from staging to src/workflows/

n8n.workflows.export.staging: @bash bin/n8n/export.sh staging

Deploy all workflows from src/workflows/ to staging

n8n.workflows.deploy: @bash bin/n8n/deploy.sh staging

Deploy all workflows from src/workflows/ to production

n8n.workflows.deploy.prod: @bash bin/n8n/deploy.sh production

Deploy a single workflow to staging (usage: make n8n.workflow.deploy WORKFLOW=lead_scoring)

n8n.workflow.deploy: @test -n “$(WORKFLOW)” || (echo “Usage: make n8n.workflow.deploy WORKFLOW=lead_scoring” && exit 1) @WORKFLOW=$(WORKFLOW) bash bin/n8n/deploy.sh staging ```

Como verificar

  1. make n8n.workflows.export → JSONs em src/workflows/ com nomes em snake_case (só workflows ativos; active: false são excluídos)
  2. git diff src/workflows/ mostra as mudanças nos workflows
  3. make n8n.workflows.deploy → workflows importados em staging (todos substituídos)
  4. make n8n.workflow.deploy WORKFLOW=lead_scoring → apenas lead_scoring.json importado em staging
  5. make n8n.promote → deploy em produção a partir dos JSONs do repo

Documentação

— (não registrado na spec original)