AutomationFlowsSlack & Telegram › Backup & Restore N8n Workflows with Telegram, Google Drive and Form Upload

Backup & Restore N8n Workflows with Telegram, Google Drive and Form Upload

ByDaniel Nkencho @daniel-automates on n8n.io

Secure your n8n automations with this comprehensive template that automates periodic backups to Telegram for instant access while enabling flexible restores from Google Drive links or direct file uploads—ensuring quick recovery without data loss.

Event trigger★★★★☆ complexity28 nodesn8nTelegramGoogle DriveForm Trigger
Slack & Telegram Trigger: Event Nodes: 28 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #9645 — we link there as the canonical source.

This workflow follows the Form Trigger → Google Drive recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "5b97598a-3366-4294-b76d-273c00ef1fdd",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        6000,
        1040
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "33b8396b-2889-4daf-8ffb-bc11a4324448",
      "name": "Schedule Backup Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        5984,
        560
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "daysInterval": 3
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "81c12768-16bd-4103-a1eb-24af472c457a",
      "name": "Note: Schedule Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5904,
        352
      ],
      "parameters": {
        "color": 6,
        "width": 376,
        "height": 176,
        "content": "## \u23f0 Schedule Backup Trigger\n\n**Purpose:** Initiates automated workflow export every 3 days.\n\n**Note:** Adjust interval in node settings for custom frequency (e.g., daily)."
      },
      "typeVersion": 1
    },
    {
      "id": "290dfccd-f8a1-467d-a65f-9f5774e2d8ee",
      "name": "Fetch All Workflows",
      "type": "n8n-nodes-base.n8n",
      "position": [
        6208,
        560
      ],
      "parameters": {
        "filters": {},
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "58f2ba7e-aa94-43fe-a103-9ef22e1d2f2a",
      "name": "Note: Fetch Workflows",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5952,
        720
      ],
      "parameters": {
        "color": 5,
        "width": 488,
        "height": 144,
        "content": "## \ud83d\udd0d Fetch All Workflows\n\n**Purpose:** Retrieves complete list of n8n workflows via API.\n\n**Note:** Requires n8n API credential; outputs JSON array for aggregation."
      },
      "typeVersion": 1
    },
    {
      "id": "9d9356c3-9683-47a9-9a21-7ba579cbb280",
      "name": "Aggregate Workflows",
      "type": "n8n-nodes-base.aggregate",
      "position": [
        6416,
        560
      ],
      "parameters": {
        "options": {},
        "aggregate": "aggregateAllItemData"
      },
      "typeVersion": 1
    },
    {
      "id": "03200b93-3f13-47f8-a0ff-700e17e2fe6b",
      "name": "Note: Aggregate Data",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6352,
        368
      ],
      "parameters": {
        "color": 3,
        "width": 360,
        "height": 176,
        "content": "## \ud83d\udcca Aggregate Workflows\n\n**Purpose:** Combines fetched workflows into single JSON array.\n\n**Note:** Uses 'aggregateAllItemData' to prepare for file conversion."
      },
      "typeVersion": 1
    },
    {
      "id": "862faac9-bfd8-4b11-a467-2eeb0d54292d",
      "name": "Convert to Backup File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        6640,
        560
      ],
      "parameters": {
        "options": {},
        "operation": "toText",
        "sourceProperty": "data"
      },
      "typeVersion": 1.1
    },
    {
      "id": "ade96952-54bc-444c-9bdd-57fd4a798169",
      "name": "Note: Convert File",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6528,
        720
      ],
      "parameters": {
        "color": 3,
        "width": 472,
        "height": 144,
        "content": "## \ud83d\udcc4 Convert to Backup File\n\n**Purpose:** Transforms JSON array to downloadable text file.\n\n**Note:** Sources 'data' property; sets filename to 'All-n8n-workflows.txt'."
      },
      "typeVersion": 1
    },
    {
      "id": "f2b52a80-00ad-4316-aa6f-4bef50626826",
      "name": "Send Backup to Telegram",
      "type": "n8n-nodes-base.telegram",
      "position": [
        6848,
        560
      ],
      "parameters": {
        "chatId": "{{your_chat_id}}",
        "operation": "sendDocument",
        "binaryData": true,
        "additionalFields": {
          "fileName": "All-n8n-workflows.txt"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "b33de46e-16c6-4939-b9dd-ad181bb6d1b2",
      "name": "Note: Send to Telegram",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7136,
        560
      ],
      "parameters": {
        "color": 6,
        "width": 344,
        "height": 176,
        "content": "## \ud83d\udce4 Send Backup to Telegram\n\n**Purpose:** Delivers backup file to specified chat.\n\n**Note:** Replace '{{your_chat_id}}' with your Telegram chat ID; requires bot credential."
      },
      "typeVersion": 1
    },
    {
      "id": "72b820a1-4af5-45c2-bb43-e061d8d44177",
      "name": "Download Backup from Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        6240,
        1040
      ],
      "parameters": {
        "fileId": "{{your_file_id}}",
        "options": {
          "fileName": "all_workflows"
        },
        "operation": "download"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "75ebfa45-7372-41a6-868e-73c7ea4df4bc",
      "name": "Note: Download from Drive",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6352,
        896
      ],
      "parameters": {
        "color": 6,
        "width": 280,
        "height": 208,
        "content": "## \ud83d\udce5 Download Backup from Drive\n\n**Purpose:** Fetches backup text file from Google Drive.\n\n**Note:** Set '{{your_file_id}}' from Drive URL; requires OAuth credential."
      },
      "typeVersion": 1
    },
    {
      "id": "437b283a-1f3e-4297-be0d-60d9aa5a1e3b",
      "name": "Form Restore Trigger",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        6224,
        1264
      ],
      "parameters": {
        "options": {},
        "formTitle": "Upload Backup File",
        "formFields": {
          "values": [
            {
              "fieldType": "file",
              "fieldLabel": "data"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "dfe569ab-8a3d-4665-9217-0239fb82cad2",
      "name": "Note: Form Trigger",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5952,
        1424
      ],
      "parameters": {
        "color": 6,
        "width": 280,
        "height": 192,
        "content": "## \ud83d\udcdd Form Restore Trigger\n\n**Purpose:** Enables direct file upload for restore.\n\n**Note:** Use n8n form to submit local backup; connects to extraction."
      },
      "typeVersion": 1
    },
    {
      "id": "319499bc-5aab-4608-a53f-14681ff37879",
      "name": "Extract Backup Text",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        6400,
        1184
      ],
      "parameters": {
        "options": {},
        "operation": "text"
      },
      "typeVersion": 1
    },
    {
      "id": "8c8b6f65-2265-4d5e-ae5d-64e060c18a17",
      "name": "Note: Extract Text",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6304,
        1424
      ],
      "parameters": {
        "color": 3,
        "width": 392,
        "height": 192,
        "content": "## \ud83d\udcd6 Extract Backup Text\n\n**Purpose:** Reads text content from downloaded or uploaded file.\n\n**Note:** Outputs raw JSON string to 'data' property for parsing."
      },
      "typeVersion": 1
    },
    {
      "id": "c364c0f4-956c-4893-8cfa-2c3f49b87d53",
      "name": "Parse Backup JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        6576,
        1184
      ],
      "parameters": {
        "jsCode": "// The input from the previous node is an array of items. We'll work with the first item.\nconst item = items[0];\n\n// --- IMPORTANT ---\n// The 'Extract from File' node will place the file's content into a property.\n// You may need to adjust 'fileContent' to match the actual property name from that node.\nconst jsonString = item.json.data;\n\nif (!jsonString) {\n  throw new Error(\"The property 'fileContent' was not found in the input data. Please check the output of the 'Extract from File' node and update the property name in this code.\");\n}\n\n// Parse the large JSON string into an array of individual workflow objects.\nconst workflows = JSON.parse(jsonString);\n\n// List of settings properties that are not supported by the n8n API\nconst unsupportedSettingsProperties = [\n  'executionOrder',\n  'callerPolicy', \n  'errorWorkflow',\n  'timeSavedPerExecution',\n  'executionTimeout',\n  'maxExecutionTimeout'\n];\n\n// Return each workflow as a separate item.\n// For each item, convert the workflow object back into a string\n// and place it in a property called 'data'.\nreturn workflows.map(workflow => {\n  // Extract workflow name and ID for easier reference\n  const workflowName = workflow.name || 'Unnamed Workflow';\n  const workflowId = workflow.id || 'No ID';\n  \n  // Create a cleaned copy of the workflow\n  const cleanedWorkflow = { ...workflow };\n  \n  // Clean up the settings object by removing unsupported properties\n  if (cleanedWorkflow.settings) {\n    const cleanedSettings = { ...cleanedWorkflow.settings };\n    \n    // Remove unsupported properties\n    unsupportedSettingsProperties.forEach(prop => {\n      delete cleanedSettings[prop];\n    });\n    \n    cleanedWorkflow.settings = cleanedSettings;\n  }\n  \n  // Remove properties that shouldn't be included when creating new workflows\n  delete cleanedWorkflow.id;           // Let n8n assign a new ID\n  delete cleanedWorkflow.createdAt;    // Will be set by n8n\n  delete cleanedWorkflow.updatedAt;    // Will be set by n8n\n  delete cleanedWorkflow.versionId;    // Will be set by n8n\n  delete cleanedWorkflow.shared;       // Will be handled by n8n\n  delete cleanedWorkflow.triggerCount; // Will be reset by n8n\n  \n  // Clean up staticData - remove if empty or clean node-specific data\n  if (cleanedWorkflow.staticData) {\n    const cleanedStaticData = { ...cleanedWorkflow.staticData };\n    // Remove any node-specific data that might reference old node IDs\n    Object.keys(cleanedStaticData).forEach(key => {\n      if (key.startsWith('node:')) {\n        delete cleanedStaticData[key];\n      }\n    });\n    // Remove staticData entirely if it's empty after cleaning\n    if (Object.keys(cleanedStaticData).length === 0) {\n      delete cleanedWorkflow.staticData;\n    } else {\n      cleanedWorkflow.staticData = cleanedStaticData;\n    }\n  }\n  \n  // Keep pinData as it contains important test/development data\n  // Only remove pinData if it's undefined, but preserve empty objects\n  \n  // Clean up meta object - remove or clean problematic properties\n  if (cleanedWorkflow.meta) {\n    const cleanedMeta = { ...cleanedWorkflow.meta };\n    // Remove properties that might cause issues with new workflow creation\n    delete cleanedMeta.templateCredsSetupCompleted;\n    delete cleanedMeta.instanceId;\n    \n    // Remove meta entirely if it's empty after cleaning\n    if (Object.keys(cleanedMeta).length === 0) {\n      delete cleanedWorkflow.meta;\n    } else {\n      cleanedWorkflow.meta = cleanedMeta;\n    }\n  }\n  \n  // Clean webhook IDs from nodes that might conflict\n  if (cleanedWorkflow.nodes) {\n    cleanedWorkflow.nodes = cleanedWorkflow.nodes.map(node => {\n      const cleanedNode = { ...node };\n      \n      // Remove webhookId property that might reference old webhook instances\n      if (cleanedNode.webhookId) {\n        delete cleanedNode.webhookId;\n      }\n      \n      return cleanedNode;\n    });\n  }\n  \n  return {\n    json: {\n      data: JSON.stringify(cleanedWorkflow),\n      workflowName: workflowName,\n      originalId: workflowId,\n      // Additional metadata for debugging\n      hasSettings: !!workflow.settings,\n      nodeCount: workflow.nodes ? workflow.nodes.length : 0\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "05297227-aff4-4c99-a45d-c73f7c4c15fa",
      "name": "Note: Parse JSON",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        6752,
        1424
      ],
      "parameters": {
        "color": 3,
        "width": 456,
        "height": 176,
        "content": "## \ud83d\udd04 Parse Backup JSON\n\n**Purpose:** Cleans and splits JSON into individual workflow items.\n\n**Note:** Removes IDs, unsupported settings; outputs one item per workflow with metadata."
      },
      "typeVersion": 1
    },
    {
      "id": "8b7750d5-5edb-4e1c-8abf-6124bc5de56a",
      "name": "Process Each Workflow",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        6752,
        1024
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "2c33e527-7e91-4f55-be2e-92d6b2cbbeec",
      "name": "Note: Workflow Loop",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7104,
        864
      ],
      "parameters": {
        "color": 5,
        "width": 360,
        "height": 192,
        "content": "## \ud83d\udd04 Process Each Workflow\n\n**Purpose:** Loops over parsed items for sequential API calls.\n\n**Note:** Uses SplitInBatches to handle one workflow at a time; returns to loop after processing."
      },
      "typeVersion": 1
    },
    {
      "id": "74eaf063-91e3-4bfd-a52e-4284fe317a89",
      "name": "Check Workflow Existence",
      "type": "n8n-nodes-base.n8n",
      "position": [
        6944,
        1088
      ],
      "parameters": {
        "filters": {
          "name": "={{ $json.workflowName }}"
        },
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "a7d3a105-06bb-47de-90ce-f0c63ac6f99b",
      "name": "If Workflow Exists",
      "type": "n8n-nodes-base.if",
      "position": [
        7104,
        1088
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b384d46d-cd29-4362-8e36-e1b563329156",
              "operator": {
                "type": "string",
                "operation": "notExists",
                "singleValue": true
              },
              "leftValue": "={{ $json.name }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "ff3a4413-c015-4b89-a5b8-02b4329669a0",
      "name": "Create New Workflow",
      "type": "n8n-nodes-base.n8n",
      "onError": "continueErrorOutput",
      "position": [
        7504,
        1200
      ],
      "parameters": {
        "operation": "create",
        "requestOptions": {},
        "workflowObject": "={{ $('Process Each Workflow').item.json.data }}"
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "12136a58-7361-4693-ae20-09f29c5c2357",
      "name": "Update Existing Workflow",
      "type": "n8n-nodes-base.n8n",
      "position": [
        7280,
        1216
      ],
      "parameters": {
        "operation": "update",
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "requestOptions": {},
        "workflowObject": "={{ $('Process Each Workflow').item.json.data }}"
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "f9de86be-f71a-449d-8968-1353d04dd32c",
      "name": "Wait for Completion",
      "type": "n8n-nodes-base.wait",
      "position": [
        7696,
        1216
      ],
      "parameters": {},
      "typeVersion": 1.1
    },
    {
      "id": "9a316313-8f57-4376-90d4-1c5d68f03a7a",
      "name": "Note: Wait Delay",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        7680,
        1008
      ],
      "parameters": {
        "color": 2,
        "width": 328,
        "height": 176,
        "content": "## \u23f3 Wait for Completion\n\n**Purpose:** Pauses between API calls to avoid rate limits.\n\n**Note:** Default 1s delay; increase to 5-10s for large batches."
      },
      "typeVersion": 1
    },
    {
      "id": "9c3e12fb-9375-4c5c-b19e-e67c7a717599",
      "name": "Overview Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5280,
        368
      ],
      "parameters": {
        "color": 4,
        "width": 600,
        "height": 1256,
        "content": "# Automated n8n Workflow Backup & Multi-Path Restore\n\n## \ud83d\udccb What This Template Does\nThis template automates backing up all n8n workflows to a Telegram-delivered text file every 3 days and restores them via Google Drive download or direct form upload using create-or-update logic.\n\n## \ud83d\udd27 Prerequisites\n- Active n8n instance with API access\n- Telegram bot and chat ID\n- Google Drive account (for Drive restores)\n\n## \ud83d\udd11 Required Credentials\n\n### n8n API Setup\n1. Settings \u2192 n8n API \u2192 Enable & generate key\n2. Add as 'n8n API' credential\n\n### Telegram API Setup\n1. @BotFather \u2192 Create bot \u2192 Get token\n2. Note chat ID via @userinfobot\n3. Add as 'Telegram API' credential\n\n### Google Drive OAuth2 API Setup\n1. Google Cloud \u2192 Credentials \u2192 OAuth Client ID\n2. Enable Drive API, add redirect URI\n3. Connect as 'Google Drive OAuth2 API'\n\n## \u2699\ufe0f Configuration Steps\n1. Import JSON to n8n\n2. Assign credentials to nodes\n3. Set Telegram chat ID\n4. Update Drive file ID (if using Drive path)\n5. Test backup via Schedule execution\n6. Test restore via manual or form trigger\n\n## \ud83c\udfaf Use Cases\n- Backup production workflows to Telegram for sharing\n- Restore from Drive after migrations\n- Sync templates across instances via upload\n- Archive educational automations for reuse\n\n## \u26a0\ufe0f Troubleshooting\n- Empty backups: Check API read permissions\n- Parse errors: Validate JSON in file\n- Rate limits: Extend Wait duration\n- Upload fails: Use small test file first"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Manual Trigger": {
      "main": [
        [
          {
            "node": "Download Backup from Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Backup JSON": {
      "main": [
        [
          {
            "node": "Process Each Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Workflow Exists": {
      "main": [
        [
          {
            "node": "Create New Workflow",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update Existing Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate Workflows": {
      "main": [
        [
          {
            "node": "Convert to Backup File",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create New Workflow": {
      "main": [
        [
          {
            "node": "Wait for Completion",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Process Each Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Backup Text": {
      "main": [
        [
          {
            "node": "Parse Backup JSON",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch All Workflows": {
      "main": [
        [
          {
            "node": "Aggregate Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Completion": {
      "main": [
        [
          {
            "node": "Process Each Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Form Restore Trigger": {
      "main": [
        [
          {
            "node": "Extract Backup Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Each Workflow": {
      "main": [
        [],
        [
          {
            "node": "Check Workflow Existence",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert to Backup File": {
      "main": [
        [
          {
            "node": "Send Backup to Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Backup Trigger": {
      "main": [
        [
          {
            "node": "Fetch All Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Workflow Existence": {
      "main": [
        [
          {
            "node": "If Workflow Exists",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Existing Workflow": {
      "main": [
        [
          {
            "node": "Process Each Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Backup from Drive": {
      "main": [
        [
          {
            "node": "Extract Backup Text",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Secure your n8n automations with this comprehensive template that automates periodic backups to Telegram for instant access while enabling flexible restores from Google Drive links or direct file uploads—ensuring quick recovery without data loss.

Source: https://n8n.io/workflows/9645/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

Effortlessly delete unused or inactive workflows from your n8n instance while automatically backing them up as .json files into your Google Drive. Keep your instance clean, fast, and organized — no mo

Form Trigger, Telegram, Google Drive +1
Slack & Telegram

Automatically transform any website URL into a complete portfolio entry with professional screenshots and AI-generated Upwork project descriptions. Freelancers building their Upwork/portfolio from pas

HTTP Request, Google Drive, Google Sheets +2
Slack & Telegram

✨😃Automated Workflow Backups to Google Drive. Uses manualTrigger, splitInBatches, scheduleTrigger, googleDrive. Event-driven trigger; 22 nodes.

Google Drive, n8n, Telegram
Slack & Telegram

This workflow automates the process of backing up your n8n workflows to Google Drive daily. It creates timestamped folders, saves workflows as JSON files, and manages old backups by retaining only the

Google Drive, n8n, Telegram
Slack & Telegram

Stop the panic attacks. We've all been there - accidentally deleted a workflow that took hours to build, or worse, corrupted your entire automation setup. This workflow is your safety net.

Google Drive, n8n, GitHub +2