AutomationFlowsDevOps › Automated N8n Workflows Backup on Gitlab with Username Organization

Automated N8n Workflows Backup on Gitlab with Username Organization

ByOneclick AI Squad @oneclick-ai on n8n.io

This solution ensures the secure backup and version control of your self-hosted n8n workflows by storing them in a GitLab repository. It compares current workflows with their GitLab counterparts, updates files when differences are detected, and organizes them in user-specific…

Event trigger★★★★☆ complexity15 nodesn8nGitLabEmail Send
DevOps Trigger: Event Nodes: 15 Complexity: ★★★★☆ Added:

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

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
{
  "id": "5ZZy57tVLfqtQZfF",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Automated Backup of n8n Workflows to GitLab Organized by Username",
  "tags": [],
  "nodes": [
    {
      "id": "79975f6a-5aa3-4452-ba09-b489eb8c197e",
      "name": "Manual Backup Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -820,
        35
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "2d5d5165-ba45-410c-8c5a-37c142b24cc1",
      "name": "Scheduled Weekly Backup",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -820,
        235
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                5
              ],
              "triggerAtHour": 18
            }
          ]
        }
      },
      "notesInFlow": false,
      "typeVersion": 1.2
    },
    {
      "id": "6662cc05-fe42-4f80-a59a-ba670ed143f2",
      "name": "Fetch N8N Workflows",
      "type": "n8n-nodes-base.n8n",
      "position": [
        -600,
        135
      ],
      "parameters": {
        "filters": {},
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "08d1c5cc-725b-4c9b-a7e4-55df5cd74a27",
      "name": "Prepare Backup Metadata",
      "type": "n8n-nodes-base.set",
      "position": [
        -380,
        135
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "backup-date",
              "name": "backupDate",
              "type": "string",
              "value": "={{ $now.setZone('UTC').toFormat('yyyy-MM-dd') }}"
            },
            {
              "id": "backup-path",
              "name": "backupPath",
              "type": "string",
              "value": "=backups/{{ $now.setZone('UTC').toFormat('yyyy') }}/{{ $now.setZone('UTC').toFormat('MM') }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.3
    },
    {
      "id": "cbae944a-2622-4ae7-99c1-56efc56d07cf",
      "name": "Process Each Workflow",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        -160,
        135
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "693af3e9-5e9c-44c6-84a3-9a7c7dcca189",
      "name": "Format Workflow for GitLab",
      "type": "n8n-nodes-base.set",
      "position": [
        60,
        -140
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "workflow-data",
              "name": "workflowData",
              "type": "object",
              "value": "={{\n  {\n    \"id\": $json.id,\n    \"name\": $json.name,\n    \"active\": $json.active,\n    \"nodes\": $json.nodes,\n    \"connections\": $json.connections,\n    \"settings\": $json.settings,\n    \"staticData\": $json.staticData,\n    \"tags\": $json.tags,\n    \"versionId\": $json.versionId,\n    \"triggerCount\": $json.triggerCount,\n    \"createdAt\": $json.createdAt,\n    \"updatedAt\": $json.updatedAt\n  }\n}}"
            },
            {
              "id": "creator-name",
              "name": "creatorName",
              "type": "string",
              "value": "={{ $json.name.toLowerCase().includes('vrushti') ? 'vrushti' : $json.name.toLowerCase().includes('poojan') ? 'poojan' : $json.name.toLowerCase().includes('pragnesh') ? 'pragnesh' : $json.name.toLowerCase().includes('ajay') ? 'ajay' : 'general' }}"
            },
            {
              "id": "file-name",
              "name": "fileName",
              "type": "string",
              "value": "={{ $json.name.replace(/[^a-zA-Z0-9\\-_]/g, '_').replace(/_+/g, '_').replace(/^_|_$/g, '') }}.json"
            },
            {
              "id": "file-path",
              "name": "filePath",
              "type": "string",
              "value": "=n8n-workflows/{{ $json.name.toLowerCase().includes('vrushti') ? 'vrushti' : $json.name.toLowerCase().includes('poojan') ? 'poojan' : $json.name.toLowerCase().includes('pragnesh') ? 'pragnesh' : $json.name.toLowerCase().includes('ajay') ? 'ajay' : 'general' }}/{{ $json.name.replace(/[^a-zA-Z0-9\\-_]/g, '_').replace(/_+/g, '_').replace(/^_|_$/g, '') }}.json"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.3
    },
    {
      "id": "dea22b1e-e1b3-4440-b757-ba70339950de",
      "name": "Rate Limit Control",
      "type": "n8n-nodes-base.wait",
      "position": [
        280,
        -140
      ],
      "parameters": {
        "amount": 2
      },
      "typeVersion": 1.1
    },
    {
      "id": "419a3294-fe3c-41e8-a863-3b9143c8fbba",
      "name": "Check Backup Status",
      "type": "n8n-nodes-base.if",
      "position": [
        720,
        -140
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "6edbebb3-1dc9-4e70-bd4b-0c02e6574808",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.error }}",
              "rightValue": "Bad request - please check your parameters"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "bf9ad468-20ad-412a-aceb-034e06795780",
      "name": "Log Backup Results",
      "type": "n8n-nodes-base.set",
      "position": [
        60,
        60
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "error-log",
              "name": "errorLog",
              "type": "string",
              "value": "=Failed to process {{ $json.fileName }}: {{ $json.error?.message || 'Unknown error' }}"
            },
            {
              "id": "success-log",
              "name": "successLog",
              "type": "string",
              "value": "=Successfully processed {{ $json.fileName }} for {{ $json.creatorName }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.3
    },
    {
      "id": "7d67c031-8c4a-409b-9c7e-69775b28abf1",
      "name": "Update Backup Summary",
      "type": "n8n-nodes-base.gitlab",
      "position": [
        940,
        35
      ],
      "parameters": {
        "owner": "gitlab-user",
        "branch": "main",
        "filePath": "={{ $('Rate Limit Control').item.json.filePath }}",
        "resource": "file",
        "operation": "edit",
        "repository": "n8n-backup",
        "fileContent": "={{ JSON.stringify( $('Rate Limit Control').item.json.workflowData, null, 2) }}",
        "commitMessage": "=Update {{ $('Rate Limit Control').item.json.fileName }} in {{ $('Rate Limit Control').item.json.creatorName }} folder via n8n automation"
      },
      "credentials": {
        "gitlabApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "continueOnFail": true
    },
    {
      "id": "52424bd4-cbce-44a9-ab17-ddf1a910a5b9",
      "name": "Send email",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        280,
        60
      ],
      "parameters": {
        "text": "Hello,\n\nThe scheduled backup of all n8n workflows has been completed successfully.\n\nAll workflows have been committed to the GitLab repository without any errors.\n\nRegards,\nn8n Automation Bot",
        "options": {},
        "subject": "n8n workflows backup notification",
        "toEmail": "abc.gmail.com",
        "fromEmail": "user@example.com",
        "emailFormat": "text"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "5447ade3-d338-4341-ac86-36e1c1379f5f",
      "name": "Create to GitLab Repository",
      "type": "n8n-nodes-base.gitlab",
      "position": [
        500,
        -140
      ],
      "parameters": {
        "owner": "gitlab-user",
        "branch": "main",
        "filePath": "={{ $json.filePath }}",
        "resource": "file",
        "repository": "n8n-backup",
        "fileContent": "={{ JSON.stringify($json.workflowData, null, 2) }}",
        "commitMessage": "=Add  {{ $json.fileName }} - {{ $json.creatorName }} folder via n8n automation"
      },
      "credentials": {
        "gitlabApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1,
      "continueOnFail": true
    },
    {
      "id": "bf1d778c-2363-46da-8197-2fc673b0b258",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -900,
        -160
      ],
      "parameters": {
        "height": 560,
        "content": "## Backup Initiation: \n\nTriggers manually or weekly to start the process "
      },
      "typeVersion": 1
    },
    {
      "id": "742d27cd-19e4-46d5-bffb-0bac0d101a58",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -630,
        -265
      ],
      "parameters": {
        "color": 3,
        "width": 380,
        "height": 560,
        "content": "## Workflow Retrieval & Prep: \n\nFetches workflows and prepares metadata"
      },
      "typeVersion": 1
    },
    {
      "id": "8c5e0911-391d-44ca-871b-8d6e20e65939",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -230,
        -265
      ],
      "parameters": {
        "color": 6,
        "width": 1340,
        "height": 560,
        "content": "## Combined Processing, Storage, and Notification: \n\nProcesses and formats workflows, saves them to GitLab with file existence checks and updates user-wise, logs results, and sends a success email."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "53da3fbb-7cb8-467b-bac5-c82a414b0096",
  "connections": {
    "Log Backup Results": {
      "main": [
        [
          {
            "node": "Send email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Rate Limit Control": {
      "main": [
        [
          {
            "node": "Create to GitLab Repository",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Backup Status": {
      "main": [
        [
          {
            "node": "Update Backup Summary",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Process Each Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch N8N Workflows": {
      "main": [
        [
          {
            "node": "Prepare Backup Metadata",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Manual Backup Trigger": {
      "main": [
        [
          {
            "node": "Fetch N8N Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process Each Workflow": {
      "main": [
        [
          {
            "node": "Log Backup Results",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Format Workflow for GitLab",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Backup Summary": {
      "main": [
        [
          {
            "node": "Process Each Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Backup Metadata": {
      "main": [
        [
          {
            "node": "Process Each Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scheduled Weekly Backup": {
      "main": [
        [
          {
            "node": "Fetch N8N Workflows",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Workflow for GitLab": {
      "main": [
        [
          {
            "node": "Rate Limit Control",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create to GitLab Repository": {
      "main": [
        [
          {
            "node": "Check Backup Status",
            "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

This solution ensures the secure backup and version control of your self-hosted n8n workflows by storing them in a GitLab repository. It compares current workflows with their GitLab counterparts, updates files when differences are detected, and organizes them in user-specific…

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

More DevOps workflows → · Browse all categories →

Related workflows

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

DevOps

Triggers manually or on schedule (03:00 daily by default) Fetches workflows tagged via n8n API Normalizes workflow names and applies tag convention Prepares JSON in the same structure as an n8n UI exp

n8n, GitLab
DevOps

Gitlab Code. Uses manualTrigger, noOp, splitInBatches, gitlab. Event-driven trigger; 21 nodes.

GitLab, n8n
DevOps

This template is inspired by Save your workflows into a GitHub repository by hikerspath and Back Up Your n8n Workflows To Github by jon-n8n.

GitLab, n8n
DevOps

Gitlab Filter. Uses manualTrigger, n8n, gitlab, stickyNote. Event-driven trigger; 16 nodes.

n8n, GitLab
DevOps

Fetches workflow definitions from within n8n, selecting only the ones that have one or more (configurable) assigned tags and then: Derives a suitable backup filename by reducing the workflow name to a

n8n, GitLab