{
  "name": "Nightly Workflow Backup to GitHub",
  "nodes": [
    {
      "parameters": {
        "content": "## Backup All n8n Workflows to GitHub Nightly\n\nEvery workflow in your n8n instance lands in a Git repo nightly - so a bad edit, a crashed server, or a deleted node is a git revert away instead of a rebuild.\n\n**Setup time:** 15 minutes  ·  **Level:** Intermediate\n\n**You'll need accounts/credentials for:** n8n API, GitHub\n\n**Replace these before running:**\n- `REPLACE_WITH_YOUR_N8N`\n- `REPLACE_WITH_OWNER`\n- `REPLACE_WITH_REPO`\n\n**Setup steps:**\n1. Create an n8n API key (Settings > n8n API) and set it in the HTTP Request node's header auth credential.\n2. Set your instance URL in the HTTP Request node (e.g. https://your-n8n.example.com/api/v1/workflows).\n3. Create a private GitHub repo, connect GitHub with a token (repo scope), and set owner/repo in the GitHub node.\n4. Activate - tomorrow morning your repo contains every workflow as JSON.\n\nFree templates and updates: navkhan103.github.io",
        "height": 640,
        "width": 400,
        "color": 4
      },
      "id": "sticky-setup",
      "name": "Setup — read me first",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        -40
      ]
    },
    {
      "parameters": {
        "content": "### How it runs\n\nStarts from **Nightly 2am**.\n\n1. A Schedule Trigger runs nightly at 2am.\n2. An HTTP Request node calls your instance's /api/v1/workflows endpoint with an API key.\n3. A Code node turns each workflow into a pretty-printed JSON file item, named by its slug.\n4. A GitHub node creates or updates each file in your backup repo - unchanged files produce no noise commits.",
        "height": 348,
        "width": 400,
        "color": 7
      },
      "id": "sticky-how",
      "name": "How it runs",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        640
      ]
    },
    {
      "parameters": {
        "content": "### If something breaks\n\nThe read and AI nodes here **retry 3× automatically** (5s apart), which absorbs rate limits and brief timeouts.\n\nNodes that **send or write deliberately do not retry** — a send that reached the far end but lost its response would otherwise fire twice, so you'd get duplicate messages or duplicate rows.\n\nTo be told when one of those fails, build a workflow starting with an **Error Trigger** node that posts to Slack or email, then set it under **three-dot menu > Settings > Error Workflow**. Do it once and point every workflow at it.",
        "height": 400,
        "width": 400,
        "color": 3
      },
      "id": "sticky-fail",
      "name": "If something breaks",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -440,
        1028
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 2 * * *"
            }
          ]
        }
      },
      "id": "e8f9a0b1-0001-4000-8000-000000000001",
      "name": "Nightly 2am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "url": "https://REPLACE_WITH_YOUR_N8N/api/v1/workflows",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "options": {}
      },
      "id": "e8f9a0b1-0002-4000-8000-000000000002",
      "name": "List All Workflows",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        220,
        0
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json.data || [];\nreturn data.map(wf => {\n  const slug = wf.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || `workflow-${wf.id}`;\n  return { json: {\n    path: `workflows/${slug}.json`,\n    content: JSON.stringify({ name: wf.name, nodes: wf.nodes, connections: wf.connections, settings: wf.settings }, null, 2),\n    message: `backup: ${wf.name}`\n  } };\n});"
      },
      "id": "e8f9a0b1-0003-4000-8000-000000000003",
      "name": "One File per Workflow",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        0
      ]
    },
    {
      "parameters": {
        "resource": "file",
        "operation": "edit",
        "owner": {
          "__rl": true,
          "mode": "list",
          "value": "REPLACE_WITH_OWNER"
        },
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "REPLACE_WITH_REPO"
        },
        "filePath": "={{ $json.path }}",
        "fileContent": "={{ $json.content }}",
        "commitMessage": "={{ $json.message }}"
      },
      "id": "e8f9a0b1-0004-4000-8000-000000000004",
      "name": "Commit to GitHub",
      "type": "n8n-nodes-base.github",
      "typeVersion": 1.1,
      "position": [
        660,
        0
      ]
    }
  ],
  "connections": {
    "Nightly 2am": {
      "main": [
        [
          {
            "node": "List All Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List All Workflows": {
      "main": [
        [
          {
            "node": "One File per Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "One File per Workflow": {
      "main": [
        [
          {
            "node": "Commit to GitHub",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}