Bem-vindo ao Mundo do n8n!
O n8n é uma ferramenta poderosa de automação de workflows que conecta suas aplicações e automatiza processos complexos.
Código Aberto
Open source, self-hosted e extensível
300+ Integrações
Conecte qualquer aplicação ou serviço
Interface Visual
Editor drag-and-drop intuitivo
O que é o n8n?
- Ferramenta de automação de workflows
- Editor visual com nós conectáveis
- Triggers automáticos e manuais
- Processamento de dados em tempo real
- Execução local ou em nuvem
Por que usar o n8n?
Instalação Rápida
Docker
docker run -it --rm \
--name n8n \
-p 5678:5678 \
-v ~/.n8n:/home/node/.n8n \
n8nio/n8n
NPM
npm install n8n -g
n8n start
Binário
# Download do GitHub
# Executar diretamente
./n8n
Acesso: Após a instalação, acesse http://localhost:5678 para começar!
Casos de Uso Populares
Sincronização de dados
Posts automáticos em redes sociais
Relatórios automáticos
Processamento de pedidos
Backup automático
Gestão de leads
Agendamento de tarefas
Geração de documentos
Conceitos Fundamentais
Workflows
Um workflow é uma sequência de nós conectados que processam dados automaticamente.
Exemplo: Webhook → Processar dados → Enviar email
Nós (Nodes)
Cada nó representa uma ação específica ou integração com um serviço.
Simulador Visual de Workflow
Tipos de Triggers
Cron Trigger
Executa em horários específicos
0 9 * * 1-5Todo dia útil às 9h
Webhook
Ativado por requisições HTTP
POST /webhook/abc123URL única para cada workflow
Email Trigger
Monitora emails recebidos
IMAP/POP3Verifica caixa de entrada
Expressões e Dados
Expressões Básicas
{{ $json.name }}
Acessa propriedade do JSON
{{ $now.format('YYYY-MM-DD') }}
Data atual formatada
{{ $('Node Name').first().json.data }}
Dados de outro nó
Funções Úteis
{{ $json.email.toLowerCase() }}
Converter para minúsculas
{{ Math.round($json.price * 1.1) }}
Cálculos matemáticos
{{ $json.items.length }}
Tamanho de array
Workflows Básicos
1. Workflow de Backup Automático
Estrutura do Workflow
Configuração JSON
{
"nodes": [
{
"name": "Cron Trigger",
"type": "n8n-nodes-base.cron",
"parameters": {
"rule": {
"hour": 2,
"minute": 0
}
}
},
{
"name": "MySQL Backup",
"type": "n8n-nodes-base.mysql",
"parameters": {
"operation": "executeQuery",
"query": "SELECT * FROM users",
"options": {
"largeNumbersOutput": "text"
}
}
},
{
"name": "Google Drive Upload",
"type": "n8n-nodes-base.googleDrive",
"parameters": {
"operation": "upload",
"name": "backup_{{ $now.format('YYYY-MM-DD') }}.json",
"driveId": "backup-folder",
"binaryData": true
}
}
],
"connections": {
"Cron Trigger": {
"main": [[{"node": "MySQL Backup", "type": "main", "index": 0}]]
},
"MySQL Backup": {
"main": [[{"node": "Google Drive Upload", "type": "main", "index": 0}]]
}
}
}
2. Monitor de Website com Notificações
Fluxo do Workflow
Código do Workflow
{
"nodes": [
{
"name": "Every 5 minutes",
"type": "n8n-nodes-base.interval",
"parameters": {
"interval": 5,
"unit": "minutes"
}
},
{
"name": "Check Website",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://meusite.com",
"options": {
"timeout": 10000,
"followRedirect": false
}
}
},
{
"name": "Is Site Down?",
"type": "n8n-nodes-base.if",
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.statusCode }}",
"operation": "notEqual",
"value2": 200
}
]
}
}
},
{
"name": "Send Alert",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#alerts",
"text": "🚨 WEBSITE DOWN!\nURL: {{ $('Check Website').first().json.url }}\nStatus: {{ $('Check Website').first().json.statusCode }}\nTime: {{ $now.format('DD/MM/YYYY HH:mm:ss') }}"
}
}
]
}
3. Processamento de Formulário Web
Estrutura Completa
Configuração Detalhada
{
"name": "Form Processor",
"nodes": [
{
"name": "Form Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": {
"httpMethod": "POST",
"path": "contact-form",
"options": {
"rawBody": false
}
}
},
{
"name": "Validate Data",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "const data = items[0].json;\n\n// Validações\nconst errors = [];\n\nif (!data.name || data.name.length < 2) {\n errors.push('Nome é obrigatório');\n}\n\nif (!data.email || !data.email.includes('@')) {\n errors.push('Email inválido');\n}\n\nif (!data.message || data.message.length < 10) {\n errors.push('Mensagem muito curta');\n}\n\nif (errors.length > 0) {\n throw new Error('Validation failed: ' + errors.join(', '));\n}\n\n// Sanitização\ndata.name = data.name.trim();\ndata.email = data.email.toLowerCase().trim();\ndata.message = data.message.trim();\ndata.created_at = new Date().toISOString();\n\nreturn [{ json: data }];"
}
},
{
"name": "Save to Sheets",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "append",
"sheetId": "1ABC123DEF456...",
"range": "A:E",
"options": {
"valueInputOption": "USER_ENTERED"
},
"values": [
[
"={{ $json.name }}",
"={{ $json.email }}",
"={{ $json.message }}",
"={{ $json.created_at }}",
"pending"
]
]
}
},
{
"name": "Send Confirmation",
"type": "n8n-nodes-base.emailSend",
"parameters": {
"fromEmail": "noreply@empresa.com",
"toEmail": "={{ $json.email }}",
"subject": "Confirmação - Recebemos sua mensagem",
"text": "Olá {{ $json.name }},\n\nRecebemos sua mensagem e entraremos em contato em breve.\n\nObrigado!"
}
}
]
}
4. Workflow Interativo - Teste Agora!
Simule um Formulário
Log do Workflow
Integrações Populares
300+ Integrações Disponíveis
Conecte n8n com praticamente qualquer serviço que você usa!
Google Workspace
Gmail Automation
{
"name": "Gmail Auto-Reply",
"trigger": "Gmail - New Email",
"conditions": {
"subject": "contains 'urgent'",
"from": "not internal domain"
},
"actions": [
"Parse email content",
"Generate AI response",
"Send reply with template"
]
}
Google Sheets Integration
{
"operations": [
"Read rows",
"Append data",
"Update cells",
"Create sheets",
"Format data"
],
"use_cases": [
"CRM data sync",
"Report generation",
"Form responses",
"Inventory tracking"
]
}
Google Drive Files
{
"file_operations": [
"Upload files",
"Download content",
"Create folders",
"Share permissions",
"Backup automation"
]
}
Comunicação
Slack Bot Automation
{
"triggers": [
"Slash commands",
"Message reactions",
"Channel mentions",
"Direct messages"
],
"responses": [
"Send formatted messages",
"Create threads",
"Update statuses",
"Schedule reminders"
]
}
Teams Integration
{
"features": [
"Post to channels",
"Send direct messages",
"Create meetings",
"Share files",
"Update calendar"
]
}
Discord Bots
{
"bot_commands": [
"Server moderation",
"Welcome messages",
"Role management",
"Automated responses",
"Game integrations"
]
}
E-commerce & CRM
Shopify Automation
{
"events": [
"New orders",
"Product updates",
"Customer registration",
"Inventory changes"
],
"actions": [
"Send order confirmations",
"Update inventory",
"Generate invoices",
"Track shipments"
]
}
HubSpot CRM
{
"crm_operations": [
"Create contacts",
"Update deals",
"Track activities",
"Generate reports",
"Email sequences"
]
}
WooCommerce
{
"wordpress_integration": [
"Order processing",
"Customer data sync",
"Product management",
"Email marketing",
"Analytics tracking"
]
}
Workflow: Sincronização Multi-Plataforma
Cenário: Lead Management
Quando um novo lead é capturado em um formulário web, automaticamente:
Código do Workflow
{
"name": "Lead Sync Multi-Platform",
"nodes": [
{
"name": "Webhook Lead Capture",
"type": "n8n-nodes-base.webhook",
"parameters": {
"httpMethod": "POST",
"path": "new-lead"
}
},
{
"name": "Process Lead Data",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Standardize lead data\nconst lead = items[0].json;\n\nconst standardizedLead = {\n firstName: lead.first_name || lead.name?.split(' ')[0],\n lastName: lead.last_name || lead.name?.split(' ').slice(1).join(' '),\n email: lead.email?.toLowerCase(),\n phone: lead.phone,\n company: lead.company,\n source: lead.utm_source || 'website',\n createdAt: new Date().toISOString()\n};\n\nreturn [{ json: standardizedLead }];"
}
},
{
"name": "Save to HubSpot",
"type": "n8n-nodes-base.hubspot",
"parameters": {
"resource": "contact",
"operation": "create",
"properties": {
"firstname": "={{ $json.firstName }}",
"lastname": "={{ $json.lastName }}",
"email": "={{ $json.email }}",
"phone": "={{ $json.phone }}",
"company": "={{ $json.company }}"
}
}
},
{
"name": "Add to MailChimp",
"type": "n8n-nodes-base.mailchimp",
"parameters": {
"operation": "subscribe",
"list": "main-list",
"email": "={{ $json.email }}",
"mergeFields": {
"FNAME": "={{ $json.firstName }}",
"LNAME": "={{ $json.lastName }}"
}
}
},
{
"name": "Notify Slack",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#sales",
"text": "🎉 Novo Lead!\n👤 {{ $json.firstName }} {{ $json.lastName }}\n📧 {{ $json.email }}\n🏢 {{ $json.company }}\n🔗 Fonte: {{ $json.source }}"
}
},
{
"name": "Log to Sheets",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "append",
"values": [
[
"={{ $json.firstName }}",
"={{ $json.lastName }}",
"={{ $json.email }}",
"={{ $json.phone }}",
"={{ $json.company }}",
"={{ $json.source }}",
"={{ $json.createdAt }}"
]
]
}
}
]
}
APIs e Webhooks Personalizados
HTTP Request Node
Para integrar com APIs que não têm nó específico:
{
"name": "Custom API Call",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.exemplo.com/webhook",
"authentication": "headerAuth",
"headerAuth": {
"name": "Authorization",
"value": "Bearer {{ $credentials.apiToken }}"
},
"body": {
"contentType": "json",
"jsonBody": {
"event": "user_registered",
"data": {
"user_id": "={{ $json.id }}",
"email": "={{ $json.email }}",
"timestamp": "={{ $now }}"
}
}
},
"options": {
"timeout": 30000,
"retry": {
"enabled": true,
"times": 3
}
}
}
}
Webhook Security
Configurações de segurança para webhooks:
{
"webhook_security": {
"authentication": {
"method": "header",
"headerName": "X-API-Key",
"expectedValue": "{{ $credentials.webhookSecret }}"
},
"validation": {
"signature": {
"algorithm": "sha256",
"header": "X-Hub-Signature-256",
"secret": "{{ $credentials.webhookSecret }}"
}
},
"rate_limiting": {
"requests_per_minute": 60,
"burst": 10
},
"ip_whitelist": [
"192.168.1.0/24",
"10.0.0.0/8"
]
}
}
Workflows Avançados
1. AI-Powered Content Generation
Fluxo Inteligente
Implementação com AI
{
"name": "AI Content Pipeline",
"nodes": [
{
"name": "RSS Feed Monitor",
"type": "n8n-nodes-base.rssFeedRead",
"parameters": {
"url": "https://feeds.example.com/tech-news"
}
},
{
"name": "OpenAI Summarizer",
"type": "n8n-nodes-base.openAi",
"parameters": {
"model": "gpt-4",
"prompt": "Resuma este artigo em 280 caracteres para Twitter, mantendo as informações mais importantes:\n\n{{ $json.content }}",
"maxTokens": 150,
"temperature": 0.7
}
},
{
"name": "Generate Image",
"type": "n8n-nodes-base.openAi",
"parameters": {
"model": "dall-e-3",
"prompt": "Create a modern, minimalist illustration representing: {{ $json.title }}",
"size": "1024x1024",
"quality": "standard"
}
},
{
"name": "Sentiment Analysis",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Análise de sentimento simples\nconst text = items[0].json.summary.toLowerCase();\n\nconst positiveWords = ['good', 'great', 'excellent', 'amazing', 'breakthrough'];\nconst negativeWords = ['bad', 'terrible', 'awful', 'disaster', 'crisis'];\n\nlet sentiment = 'neutral';\nlet score = 0;\n\npositiveWords.forEach(word => {\n if (text.includes(word)) score += 1;\n});\n\nnegativeWords.forEach(word => {\n if (text.includes(word)) score -= 1;\n});\n\nif (score > 0) sentiment = 'positive';\nif (score < 0) sentiment = 'negative';\n\nreturn [{\n json: {\n ...items[0].json,\n sentiment: sentiment,\n sentimentScore: score\n }\n}];"
}
},
{
"name": "Post to Twitter",
"type": "n8n-nodes-base.twitter",
"parameters": {
"text": "{{ $('OpenAI Summarizer').first().json.choices[0].message.content }}\n\n#TechNews #AI",
"additionalFields": {
"media": "{{ $('Generate Image').first().json.data[0].url }}"
}
}
}
]
}
2. Complex Data Processing Pipeline
ETL Avançado
Processa grandes volumes de dados com transformações complexas:
Data Processing Function
{
"name": "Advanced Data Processor",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Processamento avançado de dados\nconst _ = require('lodash');\nconst moment = require('moment');\n\n// Dados de entrada\nconst rawData = items[0].json.records;\n\n// Validação e limpeza\nconst cleanData = rawData\n .filter(record => {\n // Remove registros inválidos\n return record.email && \n record.email.includes('@') &&\n record.amount && \n record.amount > 0;\n })\n .map(record => {\n // Normalização\n return {\n id: record.id,\n email: record.email.toLowerCase().trim(),\n amount: parseFloat(record.amount),\n currency: record.currency || 'USD',\n date: moment(record.date).format('YYYY-MM-DD'),\n category: record.category?.toLowerCase(),\n // Campos calculados\n quarter: moment(record.date).quarter(),\n year: moment(record.date).year(),\n month: moment(record.date).month() + 1\n };\n });\n\n// Agregações\nconst analytics = {\n totalRecords: cleanData.length,\n totalAmount: _.sumBy(cleanData, 'amount'),\n avgAmount: _.meanBy(cleanData, 'amount'),\n byCategory: _.groupBy(cleanData, 'category'),\n byMonth: _.groupBy(cleanData, 'month'),\n topCustomers: _.chain(cleanData)\n .groupBy('email')\n .map((orders, email) => ({\n email,\n totalAmount: _.sumBy(orders, 'amount'),\n orderCount: orders.length\n }))\n .orderBy('totalAmount', 'desc')\n .take(10)\n .value()\n};\n\nreturn [\n { json: { processedData: cleanData } },\n { json: { analytics: analytics } }\n];"
}
}
3. Error Handling & Retry Logic
Estratégias de Recuperação
Try/Catch Global
Captura erros em todo o workflow
Retry com Backoff
Tentativas com delay exponencial
Dead Letter Queue
Armazena falhas para análise
Error Handler Implementation
{
"name": "Robust Error Handler",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Sistema robusto de tratamento de erros\nconst maxRetries = 3;\nconst baseDelay = 1000; // 1 segundo\n\nasync function executeWithRetry(operation, data, attempt = 1) {\n try {\n // Simula operação que pode falhar\n const result = await operation(data);\n return { success: true, data: result };\n \n } catch (error) {\n console.error(`Attempt ${attempt} failed:`, error.message);\n \n if (attempt >= maxRetries) {\n // Máximo de tentativas atingido\n return {\n success: false,\n error: error.message,\n attempts: attempt,\n timestamp: new Date().toISOString(),\n originalData: data\n };\n }\n \n // Calcula delay exponencial\n const delay = baseDelay * Math.pow(2, attempt - 1);\n console.log(`Retrying in ${delay}ms...`);\n \n // Aguarda antes da próxima tentativa\n await new Promise(resolve => setTimeout(resolve, delay));\n \n // Recursão para nova tentativa\n return executeWithRetry(operation, data, attempt + 1);\n }\n}\n\n// Exemplo de uso\nconst apiCall = async (data) => {\n // Simula chamada de API que pode falhar\n if (Math.random() < 0.7) {\n throw new Error('API temporarily unavailable');\n }\n return { processed: true, id: data.id };\n};\n\n// Processa cada item com retry\nconst results = [];\nfor (const item of items) {\n const result = await executeWithRetry(apiCall, item.json);\n results.push({ json: result });\n}\n\nreturn results;"
}
}
4. Workflow Orchestration & Subflows
Master Workflow
Orquestra múltiplos sub-workflows:
Orchestrator Code
{
"name": "Workflow Orchestrator",
"nodes": [
{
"name": "Master Trigger",
"type": "n8n-nodes-base.webhook"
},
{
"name": "Validate Input",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Valida e prepara dados\nconst input = items[0].json;\n\nif (!input.userId || !input.action) {\n throw new Error('Missing required fields');\n}\n\n// Determina sub-workflows necessários\nconst workflows = [];\n\nif (input.action === 'user_onboarding') {\n workflows.push(\n 'email_welcome_sequence',\n 'setup_user_preferences', \n 'create_user_dashboard',\n 'assign_default_permissions'\n );\n}\n\nreturn [{\n json: {\n ...input,\n workflows: workflows,\n orchestrationId: Date.now().toString()\n }\n}];"
}
},
{
"name": "Execute Sub-Workflows",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Executa sub-workflows em paralelo\nconst data = items[0].json;\nconst results = [];\n\n// Simula execução de sub-workflows\nfor (const workflow of data.workflows) {\n results.push({\n workflow: workflow,\n status: 'completed',\n executionId: `exec_${Date.now()}_${Math.random()}`,\n startTime: new Date().toISOString(),\n duration: Math.random() * 5000 // ms\n });\n}\n\nreturn [{\n json: {\n orchestrationId: data.orchestrationId,\n userId: data.userId,\n subWorkflows: results,\n overallStatus: 'completed',\n completedAt: new Date().toISOString()\n }\n}];"
}
}
]
}
Automações Empresariais
1. Customer Onboarding Automation
Jornada Completa do Cliente
Dia 0 - Boas-vindas
- • Email de boas-vindas personalizado
- • Criação de conta nos sistemas
- • Atribuição de representante
Dia 1 - Setup
- • Agendamento de call de onboarding
- • Envio de guia de primeiros passos
- • Acesso ao portal do cliente
Dia 7 - Follow-up
- • Pesquisa de satisfação
- • Identificação de próximos passos
- • Oferta de suporte adicional
Workflow Implementation
{
"name": "Customer Onboarding",
"nodes": [
{
"name": "New Customer Trigger",
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "new-customer"
}
},
{
"name": "Customer Data Enrichment",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "const customer = items[0].json;\n\n// Enriquece dados do cliente\nconst enrichedData = {\n ...customer,\n onboardingId: `OB_${Date.now()}`,\n customerTier: customer.contractValue > 10000 ? 'Enterprise' : 'Standard',\n assignedCSM: customer.contractValue > 50000 ? 'senior-csm' : 'standard-csm',\n onboardingTrack: customer.industry === 'finance' ? 'compliance-focused' : 'standard',\n timeZone: customer.timeZone || 'UTC',\n language: customer.language || 'en'\n};\n\nreturn [{ json: enrichedData }];"
}
},
{
"name": "Create HubSpot Contact",
"type": "n8n-nodes-base.hubspot",
"parameters": {
"resource": "contact",
"operation": "create",
"properties": {
"email": "={{ $json.email }}",
"firstname": "={{ $json.firstName }}",
"lastname": "={{ $json.lastName }}",
"company": "={{ $json.company }}",
"phone": "={{ $json.phone }}",
"lifecyclestage": "customer",
"customer_tier": "={{ $json.customerTier }}",
"onboarding_id": "={{ $json.onboardingId }}"
}
}
},
{
"name": "Send Welcome Email",
"type": "n8n-nodes-base.emailSend",
"parameters": {
"fromEmail": "welcome@empresa.com",
"toEmail": "={{ $json.email }}",
"subject": "🎉 Bem-vindo à [Empresa], {{ $json.firstName }}!",
"htmlBody": "Olá {{ $json.firstName }},
Bem-vindo à nossa plataforma! Estamos muito animados para trabalhar com você.
Seus próximos passos:
- Acesse seu portal: portal.empresa.com
- Agende sua call de onboarding
- Explore nossos recursos
Seu representante: {{ $json.assignedCSM }}
ID do Onboarding: {{ $json.onboardingId }}
"
}
},
{
"name": "Schedule Follow-ups",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "// Agenda follow-ups automáticos\nconst customer = items[0].json;\nconst followUps = [];\n\n// Day 1 follow-up\nfollowUps.push({\n type: 'email',\n scheduleFor: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),\n template: 'day1_setup_guide',\n customerId: customer.onboardingId\n});\n\n// Day 3 check-in call\nfollowUps.push({\n type: 'calendar_invite',\n scheduleFor: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString(),\n duration: 30,\n subject: 'Onboarding Check-in Call',\n customerId: customer.onboardingId\n});\n\n// Day 7 satisfaction survey\nfollowUps.push({\n type: 'survey',\n scheduleFor: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString(),\n surveyId: 'onboarding_satisfaction',\n customerId: customer.onboardingId\n});\n\nreturn followUps.map(followUp => ({ json: followUp }));"
}
},
{
"name": "Notify Sales Team",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#sales-notifications",
"text": "🎉 Novo cliente onboarded!\n👤 {{ $json.firstName }} {{ $json.lastName }}\n🏢 {{ $json.company }}\n💰 Tier: {{ $json.customerTier }}\n🆔 Onboarding ID: {{ $json.onboardingId }}\n👨💼 CSM: {{ $json.assignedCSM }}"
}
}
]
}
2. Automated Invoice Processing
Processo de Faturamento
Billing Automation
{
"name": "Automated Billing",
"schedule": "0 9 1 * *", // 1st day of month at 9 AM
"nodes": [
{
"name": "Monthly Billing Trigger",
"type": "n8n-nodes-base.cron"
},
{
"name": "Get Active Contracts",
"type": "n8n-nodes-base.mysql",
"parameters": {
"query": "SELECT c.*, cu.email, cu.name, cu.billing_address FROM contracts c JOIN customers cu ON c.customer_id = cu.id WHERE c.status = 'active' AND c.billing_day <= DAY(NOW())"
}
},
{
"name": "Generate Invoice Data",
"type": "n8n-nodes-base.function",
"parameters": {
"functionCode": "const contracts = items[0].json;\nconst invoices = [];\n\nfor (const contract of contracts) {\n // Calculate billing period\n const today = new Date();\n const billingStart = new Date(today.getFullYear(), today.getMonth(), 1);\n const billingEnd = new Date(today.getFullYear(), today.getMonth() + 1, 0);\n \n // Calculate amount based on usage or fixed\n let amount = contract.monthly_amount;\n \n if (contract.billing_type === 'usage') {\n // Get usage data (simplified)\n amount = contract.base_amount + (contract.usage_units * contract.unit_price);\n }\n \n // Apply taxes\n const taxRate = contract.tax_rate || 0.08;\n const taxAmount = amount * taxRate;\n const totalAmount = amount + taxAmount;\n \n invoices.push({\n contractId: contract.id,\n customerId: contract.customer_id,\n customerName: contract.name,\n customerEmail: contract.email,\n invoiceNumber: `INV-${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(contract.id).padStart(4, '0')}`,\n billingPeriodStart: billingStart.toISOString().split('T')[0],\n billingPeriodEnd: billingEnd.toISOString().split('T')[0],\n subtotal: amount,\n taxAmount: taxAmount,\n totalAmount: totalAmount,\n currency: contract.currency || 'USD',\n dueDate: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], // 30 days\n status: 'pending',\n createdAt: new Date().toISOString()\n });\n}\n\nreturn invoices.map(invoice => ({ json: invoice }));"
}
},
{
"name": "Save to Database",
"type": "n8n-nodes-base.mysql",
"parameters": {
"query": "INSERT INTO invoices (contract_id, customer_id, invoice_number, billing_period_start, billing_period_end, subtotal, tax_amount, total_amount, currency, due_date, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"values": [
"={{ $json.contractId }}",
"={{ $json.customerId }}",
"={{ $json.invoiceNumber }}",
"={{ $json.billingPeriodStart }}",
"={{ $json.billingPeriodEnd }}",
"={{ $json.subtotal }}",
"={{ $json.taxAmount }}",
"={{ $json.totalAmount }}",
"={{ $json.currency }}",
"={{ $json.dueDate }}",
"{{ $json.status }}",
"={{ $json.createdAt }}"
]
}
},
{
"name": "Generate PDF Invoice",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.pdf-generator.com/v1/invoices",
"body": {
"template": "professional_invoice",
"data": {
"invoice_number": "={{ $json.invoiceNumber }}",
"customer_name": "={{ $json.customerName }}",
"billing_period": "{{ $json.billingPeriodStart }} - {{ $json.billingPeriodEnd }}",
"subtotal": "={{ $json.subtotal }}",
"tax": "={{ $json.taxAmount }}",
"total": "={{ $json.totalAmount }}",
"due_date": "={{ $json.dueDate }}"
}
}
}
},
{
"name": "Send Invoice Email",
"type": "n8n-nodes-base.emailSend",
"parameters": {
"fromEmail": "billing@empresa.com",
"toEmail": "={{ $json.customerEmail }}",
"subject": "Fatura {{ $json.invoiceNumber }} - {{ $json.customerName }}",
"htmlBody": "Segue em anexo sua fatura referente ao período {{ $json.billingPeriodStart }} - {{ $json.billingPeriodEnd }}.",
"attachments": "invoice_{{ $json.invoiceNumber }}.pdf"
}
}
]
}
3. HR Automation Suite
Employee Onboarding
Leave Management
Performance Review
Deploy em Produção
Preparando para Produção
Configurações essenciais para um ambiente robusto e seguro
1. Docker Compose para Produção
# docker-compose.production.yml
version: '3.8'
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n_prod
restart: unless-stopped
ports:
- "5678:5678"
environment:
# Database
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n_prod
- DB_POSTGRESDB_USER=n8n_user
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
# Redis Cache
- QUEUE_BULL_REDIS_HOST=redis
- QUEUE_BULL_REDIS_PORT=6379
- QUEUE_BULL_REDIS_PASSWORD=${REDIS_PASSWORD}
# Security
- N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=${N8N_ADMIN_USER}
- N8N_BASIC_AUTH_PASSWORD=${N8N_ADMIN_PASSWORD}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
# Performance
- EXECUTIONS_PROCESS=main
- EXECUTIONS_TIMEOUT=3600
- EXECUTIONS_TIMEOUT_MAX=7200
- N8N_METRICS=true
# Logs
- N8N_LOG_LEVEL=info
- N8N_LOG_OUTPUT=console,file
- N8N_LOG_FILE_LOCATION=/home/node/n8n-logs/
# URLs
- N8N_HOST=${N8N_DOMAIN}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://${N8N_DOMAIN}/
volumes:
- n8n_data:/home/node/.n8n
- n8n_logs:/home/node/n8n-logs
- /etc/localtime:/etc/localtime:ro
depends_on:
- postgres
- redis
networks:
- n8n_network
postgres:
image: postgres:15-alpine
container_name: n8n_postgres
restart: unless-stopped
environment:
- POSTGRES_DB=n8n_prod
- POSTGRES_USER=n8n_user
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_INITDB_ARGS=--encoding=UTF-8 --lc-collate=C --lc-ctype=C
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backups:/backups
networks:
- n8n_network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U n8n_user -d n8n_prod"]
interval: 30s
timeout: 10s
retries: 3
redis:
image: redis:7-alpine
container_name: n8n_redis
restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD} --maxmemory 256mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
networks:
- n8n_network
healthcheck:
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 30s
timeout: 10s
retries: 3
nginx:
image: nginx:alpine
container_name: n8n_nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
- nginx_logs:/var/log/nginx
depends_on:
- n8n
networks:
- n8n_network
# Monitoring
prometheus:
image: prom/prometheus:latest
container_name: n8n_prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/etc/prometheus/console_libraries'
- '--web.console.templates=/etc/prometheus/consoles'
- '--storage.tsdb.retention.time=30d'
- '--web.enable-lifecycle'
networks:
- n8n_network
grafana:
image: grafana/grafana:latest
container_name: n8n_grafana
restart: unless-stopped
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_USER=${GRAFANA_USER}
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
- GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
- ./grafana/datasources:/etc/grafana/provisioning/datasources
networks:
- n8n_network
# Backup automation
backup:
image: postgres:15-alpine
container_name: n8n_backup
restart: "no"
environment:
- PGPASSWORD=${POSTGRES_PASSWORD}
volumes:
- ./backups:/backups
- ./backup-scripts:/scripts:ro
command: /scripts/backup.sh
networks:
- n8n_network
profiles:
- backup
volumes:
n8n_data:
n8n_logs:
postgres_data:
redis_data:
prometheus_data:
grafana_data:
nginx_logs:
networks:
n8n_network:
driver: bridge
2. Nginx Configuration
# nginx.conf
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript
application/javascript application/xml+rss
application/json application/xml;
# Rate limiting
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=webhook:10m rate=50r/s;
# Security headers
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss: https:;" always;
# Upstream
upstream n8n_backend {
server n8n:5678;
keepalive 32;
}
# HTTP redirect to HTTPS
server {
listen 80;
server_name _;
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS server
server {
listen 443 ssl http2;
server_name your-domain.com;
# SSL configuration
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security
client_max_body_size 50M;
client_body_timeout 60s;
client_header_timeout 60s;
# Main application
location / {
limit_req zone=api burst=20 nodelay;
proxy_pass http://n8n_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
# Webhooks (higher rate limit)
location /webhook/ {
limit_req zone=webhook burst=100 nodelay;
proxy_pass http://n8n_backend;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 60s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
# Health check endpoint
location /health {
access_log off;
proxy_pass http://n8n_backend/healthz;
proxy_set_header Host $host;
}
# Block unwanted requests
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
}
}
3. Monitoring & Alerting
Prometheus Configuration
# prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "n8n_rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
scrape_configs:
- job_name: 'n8n'
static_configs:
- targets: ['n8n:5678']
metrics_path: '/metrics'
scrape_interval: 30s
scrape_timeout: 10s
- job_name: 'postgres'
static_configs:
- targets: ['postgres:5432']
- job_name: 'redis'
static_configs:
- targets: ['redis:6379']
- job_name: 'nginx'
static_configs:
- targets: ['nginx:80']
metrics_path: '/metrics'
Alert Rules
# n8n_rules.yml
groups:
- name: n8n_alerts
rules:
- alert: N8NHighErrorRate
expr: rate(n8n_workflow_executions_failed_total[5m]) > 0.1
for: 5m
labels:
severity: warning
annotations:
summary: "High workflow failure rate"
description: "N8N workflow failure rate is {{ $value }}% over the last 5 minutes"
- alert: N8NHighMemoryUsage
expr: process_resident_memory_bytes / 1024 / 1024 > 1000
for: 10m
labels:
severity: warning
annotations:
summary: "N8N high memory usage"
description: "N8N is using {{ $value }}MB of memory"
- alert: PostgresDown
expr: up{job="postgres"} == 0
for: 1m
labels:
severity: critical
annotations:
summary: "PostgreSQL is down"
description: "PostgreSQL database is not responding"
- alert: RedisDown
expr: up{job="redis"} == 0
for: 1m
labels:
severity: warning
annotations:
summary: "Redis is down"
description: "Redis cache is not responding"
4. Backup & Recovery Scripts
Automated Backup Script
#!/bin/bash
# backup.sh - Automated backup script
set -e
# Configuration
BACKUP_DIR="/backups"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30
# Database backup
echo "Starting PostgreSQL backup..."
pg_dump -h postgres -U n8n_user -d n8n_prod > "${BACKUP_DIR}/n8n_db_${DATE}.sql"
# Compress database backup
gzip "${BACKUP_DIR}/n8n_db_${DATE}.sql"
# N8N data backup
echo "Backing up n8n data..."
tar -czf "${BACKUP_DIR}/n8n_data_${DATE}.tar.gz" -C /home/node/.n8n .
# Workflow export
echo "Exporting workflows..."
curl -u "${N8N_ADMIN_USER}:${N8N_ADMIN_PASSWORD}" \
"http://n8n:5678/api/v1/workflows" \
> "${BACKUP_DIR}/workflows_${DATE}.json"
# Upload to cloud storage (example with AWS S3)
if [ "${AWS_S3_BUCKET}" ]; then
echo "Uploading to S3..."
aws s3 cp "${BACKUP_DIR}/n8n_db_${DATE}.sql.gz" \
"s3://${AWS_S3_BUCKET}/backups/database/"
aws s3 cp "${BACKUP_DIR}/n8n_data_${DATE}.tar.gz" \
"s3://${AWS_S3_BUCKET}/backups/data/"
aws s3 cp "${BACKUP_DIR}/workflows_${DATE}.json" \
"s3://${AWS_S3_BUCKET}/backups/workflows/"
fi
# Clean old backups
echo "Cleaning old backups..."
find "${BACKUP_DIR}" -name "n8n_db_*.sql.gz" -mtime +${RETENTION_DAYS} -delete
find "${BACKUP_DIR}" -name "n8n_data_*.tar.gz" -mtime +${RETENTION_DAYS} -delete
find "${BACKUP_DIR}" -name "workflows_*.json" -mtime +${RETENTION_DAYS} -delete
echo "Backup completed successfully!"
# Send notification
curl -X POST \
-H 'Content-type: application/json' \
--data "{\"text\":\"✅ N8N backup completed successfully - ${DATE}\"}" \
"${SLACK_WEBHOOK_URL}"
Recovery Script
#!/bin/bash
# restore.sh - Recovery script
set -e
if [ $# -eq 0 ]; then
echo "Usage: $0 "
echo "Example: $0 20240115_143022"
exit 1
fi
BACKUP_DATE=$1
BACKUP_DIR="/backups"
echo "Starting recovery for backup: ${BACKUP_DATE}"
# Stop n8n service
echo "Stopping n8n service..."
docker-compose stop n8n
# Restore database
echo "Restoring database..."
if [ -f "${BACKUP_DIR}/n8n_db_${BACKUP_DATE}.sql.gz" ]; then
# Drop existing database
docker-compose exec postgres psql -U n8n_user -c "DROP DATABASE IF EXISTS n8n_prod;"
docker-compose exec postgres psql -U n8n_user -c "CREATE DATABASE n8n_prod;"
# Restore from backup
gunzip -c "${BACKUP_DIR}/n8n_db_${BACKUP_DATE}.sql.gz" | \
docker-compose exec -T postgres psql -U n8n_user -d n8n_prod
echo "Database restored successfully"
else
echo "Database backup file not found!"
exit 1
fi
# Restore n8n data
echo "Restoring n8n data..."
if [ -f "${BACKUP_DIR}/n8n_data_${BACKUP_DATE}.tar.gz" ]; then
# Backup current data
docker run --rm -v n8n_data:/data -v $(pwd):/backup \
alpine tar czf /backup/n8n_data_current_backup.tar.gz -C /data .
# Clear current data
docker run --rm -v n8n_data:/data alpine rm -rf /data/*
# Restore from backup
docker run --rm -v n8n_data:/data -v "${BACKUP_DIR}":/backup \
alpine tar xzf "/backup/n8n_data_${BACKUP_DATE}.tar.gz" -C /data
echo "N8N data restored successfully"
else
echo "N8N data backup file not found!"
exit 1
fi
# Start services
echo "Starting services..."
docker-compose up -d
# Wait for services to be ready
echo "Waiting for services to start..."
sleep 30
# Verify restoration
echo "Verifying restoration..."
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:5678/healthz)
if [ "$RESPONSE" = "200" ]; then
echo "✅ Recovery completed successfully!"
# Send notification
curl -X POST \
-H 'Content-type: application/json' \
--data "{\"text\":\"✅ N8N recovery completed successfully - ${BACKUP_DATE}\"}" \
"${SLACK_WEBHOOK_URL}"
else
echo "❌ Recovery verification failed!"
exit 1
fi
5. Environment Variables Template
# .env - Production environment variables
# Domain and URLs
N8N_DOMAIN=n8n.yourcompany.com
WEBHOOK_URL=https://n8n.yourcompany.com/
# Database
POSTGRES_PASSWORD=your_very_secure_postgres_password
DB_POSTGRESDB_PASSWORD=your_very_secure_postgres_password
# Redis
REDIS_PASSWORD=your_very_secure_redis_password
# N8N Authentication
N8N_ADMIN_USER=admin
N8N_ADMIN_PASSWORD=your_very_secure_n8n_password
N8N_ENCRYPTION_KEY=your_64_character_encryption_key_here_must_be_exactly_64_chars
# Monitoring
GRAFANA_USER=admin
GRAFANA_PASSWORD=your_grafana_password
# Backup & Cloud Storage
AWS_ACCESS_KEY_ID=your_aws_access_key
AWS_SECRET_ACCESS_KEY=your_aws_secret_key
AWS_DEFAULT_REGION=us-east-1
AWS_S3_BUCKET=your-n8n-backups-bucket
# Notifications
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK
# SSL (if using Let's Encrypt)
LETSENCRYPT_EMAIL=admin@yourcompany.com
# Security
FAIL2BAN_ENABLED=true
CLOUDFLARE_API_TOKEN=your_cloudflare_token
# Performance tuning
N8N_EXECUTIONS_DATA_PRUNE=true
N8N_EXECUTIONS_DATA_MAX_AGE=168 # 7 days in hours
N8N_EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000