AutomationFlowsDevOps › Bidirectional Github Workflow Sync & Version Control for N8n Workflows

Bidirectional Github Workflow Sync & Version Control for N8n Workflows

ByWikus Bergh @rustedviking on n8n.io

Who is this for? This template is ideal for n8n administrators, automation engineers, and DevOps teams who want to maintain bidirectional synchronization between their n8n workflows and GitHub repositories. It helps teams keep their workflow backups up-to-date and ensures…

Cron / scheduled trigger★★★★☆ complexity25 nodesn8nGitHub
DevOps Trigger: Cron / scheduled Nodes: 25 Complexity: ★★★★☆ Added:
Bidirectional Github Workflow Sync & Version Control for N8n Workflows — n8n workflow card showing n8n, GitHub integration

This workflow corresponds to n8n.io template #5081 — 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": "zlH1bFBsYAWpBVVw",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "github_repo_workflows_sync",
  "tags": [
    {
      "id": "oiAlopPbS90SR7YK",
      "name": "github",
      "createdAt": "2025-06-20T15:54:28.386Z",
      "updatedAt": "2025-06-20T15:54:28.386Z"
    }
  ],
  "nodes": [
    {
      "id": "ffc98138-8afa-4cd6-8ba4-b235cc18c739",
      "name": "Create new workflow in n8n",
      "type": "n8n-nodes-base.n8n",
      "position": [
        1740,
        780
      ],
      "parameters": {
        "operation": "create",
        "requestOptions": {},
        "workflowObject": "={{ $json.toJsonString()  }}"
      },
      "typeVersion": 1
    },
    {
      "id": "d4891039-f8d2-465b-bbb6-098050f9e06c",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -260,
        280
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ]
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "174b78dc-e584-4fc1-82a2-0e58b4a98b36",
      "name": "List files from repo",
      "type": "n8n-nodes-base.github",
      "position": [
        360,
        400
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.github_account_name }}"
        },
        "filePath": "=/{{ $json.repo_workflows_path }}",
        "resource": "file",
        "operation": "list",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $json.github_repo_name }}"
        }
      },
      "typeVersion": 1,
      "alwaysOutputData": true
    },
    {
      "id": "3dcf4423-8024-4797-adee-71912ba87c2b",
      "name": "GitHub",
      "type": "n8n-nodes-base.github",
      "position": [
        800,
        400
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set GitHub Details').item.json.github_account_name }}"
        },
        "filePath": "={{ $json.path }}",
        "resource": "file",
        "operation": "get",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set GitHub Details').item.json.github_repo_name }}"
        },
        "asBinaryProperty": false,
        "additionalParameters": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "315a2e65-1c4d-46b4-b17d-b949c776c116",
      "name": "n8n",
      "type": "n8n-nodes-base.n8n",
      "position": [
        580,
        200
      ],
      "parameters": {
        "filters": {},
        "requestOptions": {}
      },
      "typeVersion": 1
    },
    {
      "id": "404e87cf-e561-4807-865a-26a6109c228f",
      "name": "Upload file",
      "type": "n8n-nodes-base.github",
      "position": [
        2400,
        -80
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set GitHub Details').item.json.github_account_name }}"
        },
        "filePath": "={{ $('Set GitHub Details').item.json.repo_workflows_path }}/{{ $node['Edit for Upload'].json.fileName }}",
        "resource": "file",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set GitHub Details').item.json.github_repo_name }}"
        },
        "fileContent": "={{ $('To base64').item.json.data }}",
        "commitMessage": "=n8n_backup_sync-{{ $node['Edit for Upload'].json.commitDate }}",
        "additionalParameters": {
          "branch": {
            "branch": "main"
          }
        }
      },
      "typeVersion": 1
    },
    {
      "id": "aee4f541-7ff4-441d-9c6b-1545676be55a",
      "name": "Json file",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        1740,
        -80
      ],
      "parameters": {
        "mode": "each",
        "options": {
          "format": true
        },
        "operation": "toJson"
      },
      "typeVersion": 1.1
    },
    {
      "id": "9047c039-ef8e-4fb2-b58c-3056f02366c7",
      "name": "To base64",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        1960,
        -80
      ],
      "parameters": {
        "options": {},
        "operation": "binaryToPropery"
      },
      "typeVersion": 1
    },
    {
      "id": "e5208d64-7f41-4be4-ad09-313aeb5fa89d",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1620,
        180
      ],
      "parameters": {
        "color": 3,
        "width": 340,
        "height": 400,
        "content": "## CHECK WHICH IS NEWER\n\n**IF TRUE** github workflow is the most recent, n8n to be updated\n\n**IF FALSE** n8n workflow is the most recent, github to be updated\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "138bd609-541a-46d6-aa1e-792e85a58c05",
      "name": "Update file",
      "type": "n8n-nodes-base.github",
      "position": [
        3220,
        560
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set GitHub Details').item.json.github_account_name }}"
        },
        "filePath": "={{ $('Set GitHub Details').item.json.repo_workflows_path }}/{{ $node['Edit for Update'].json.fileName }}",
        "resource": "file",
        "operation": "edit",
        "repository": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set GitHub Details').item.json.github_repo_name }}"
        },
        "fileContent": "={{ $('To base').item.json.data }}",
        "commitMessage": "=n8n_backup_sync-{{ $('Edit for Update').item.json.commitDate }}"
      },
      "typeVersion": 1
    },
    {
      "id": "72bd601d-fdce-4643-a26d-23e95f278110",
      "name": "Json file1",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        2560,
        560
      ],
      "parameters": {
        "mode": "each",
        "options": {
          "format": true
        },
        "operation": "toJson"
      },
      "typeVersion": 1.1
    },
    {
      "id": "3974d157-1135-4068-bc3e-b295917cd49b",
      "name": "To base",
      "type": "n8n-nodes-base.extractFromFile",
      "position": [
        2780,
        560
      ],
      "parameters": {
        "options": {},
        "operation": "binaryToPropery"
      },
      "typeVersion": 1
    },
    {
      "id": "eee2bfd1-e0e3-4db5-b4da-1bbc189f45e7",
      "name": "n8n vs GitHub",
      "type": "n8n-nodes-base.compareDatasets",
      "position": [
        1260,
        280
      ],
      "parameters": {
        "options": {},
        "mergeByFields": {
          "values": [
            {
              "field1": "id",
              "field2": "id"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "a94d4e6e-a250-4fe8-a092-a9e1697745c5",
      "name": "Update workflow in n8n",
      "type": "n8n-nodes-base.n8n",
      "position": [
        2340,
        300
      ],
      "parameters": {
        "operation": "update",
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.dataset.id }}"
        },
        "requestOptions": {},
        "workflowObject": "={{ $json.dataset.toJsonString() }}"
      },
      "typeVersion": 1
    },
    {
      "id": "09d43ee5-7a21-47cd-8bec-45ae16e8422f",
      "name": "Code - InputB",
      "type": "n8n-nodes-base.code",
      "position": [
        2120,
        300
      ],
      "parameters": {
        "language": "python",
        "pythonCode": "# Get the desired workflow name\nworkflow_id = _('If n8n before GitHub').first().json['same']['id']\n\n# Get all decoded workflow items\nall_decoded = _('Decode to json').all()\n\n# Filter for the matching one\nmatched = [\n    item.json \n    for item in all_decoded \n    if item.json.get('id') == workflow_id\n]\n\n# If there's a match, return it (or empty if none)\nif matched:\n    return [{'json': {'dataset': matched[0]}}]\nelse:\n    return []\n"
      },
      "typeVersion": 2
    },
    {
      "id": "d3be821f-a331-4dc7-993d-6af348fb1fb2",
      "name": "Code - InputA",
      "type": "n8n-nodes-base.code",
      "position": [
        2120,
        560
      ],
      "parameters": {
        "language": "python",
        "pythonCode": "# Get the desired workflow name\nworkflow_id = _('If n8n before GitHub').first().json['same']['id']\n\n# Get all decoded workflow items\nall_decoded = _('n8n').all()\n\n# Filter for the matching one\nmatched = [\n    item.json \n    for item in all_decoded \n    if item.json.get('id') == workflow_id\n]\n\n# If there's a match, return it (or empty if none)\nif matched:\n    return [{'json': {'dataset': matched[0]}}]\nelse:\n    return []\n"
      },
      "typeVersion": 2
    },
    {
      "id": "2a173594-512b-4308-b685-540bac3e2338",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        2340,
        560
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{ $json.dataset }}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "7a43de98-2d25-4d0f-9b7c-47258dc7b405",
      "name": "Edit for Upload",
      "type": "n8n-nodes-base.set",
      "position": [
        2180,
        -80
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "fe4a36ef-9f04-40e3-99bd-cc517a49b440",
              "name": "commitDate",
              "type": "string",
              "value": "={{ $now.format('dd-MM-yyyy/H:mm') }}"
            },
            {
              "id": "b0fe1bcc-e79c-4a6b-b8b4-44222c8bf4e8",
              "name": "fileName",
              "type": "string",
              "value": "={{$('n8n vs GitHub').item.json.name\n.trim().replace(/\\s+/g, '-').toLowerCase()\n}}.json"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "911736bd-1c6d-4b49-ade2-52d95f075a7f",
      "name": "Edit for Update",
      "type": "n8n-nodes-base.set",
      "position": [
        3000,
        560
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "fe4a36ef-9f04-40e3-99bd-cc517a49b440",
              "name": "commitDate",
              "type": "string",
              "value": "={{ $now.format('dd-MM-yyyy/H:mm') }}"
            },
            {
              "id": "b0fe1bcc-e79c-4a6b-b8b4-44222c8bf4e8",
              "name": "fileName",
              "type": "string",
              "value": "={{\n$('Code - InputA').item.json.dataset.name.trim().replace(/\\s+/g, '-').toLowerCase()\n}}.json"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "1193d962-fb0d-4b9e-b94c-04c8942860e4",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1620,
        -200
      ],
      "parameters": {
        "width": 1000,
        "height": 320,
        "content": "## IF ONLY IN N8N\nUpdate GitHub with the relevant workflows"
      },
      "typeVersion": 1
    },
    {
      "id": "e48eda08-7f73-46d6-ba81-f9e4b008fec3",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1620,
        640
      ],
      "parameters": {
        "color": 6,
        "width": 340,
        "height": 340,
        "content": "## IF ONLY IN GITHUB\nCreate new workflow in n8n"
      },
      "typeVersion": 1
    },
    {
      "id": "c1909c33-d3f0-4d24-b4d7-fdf1e8074398",
      "name": "If n8n before GitHub",
      "type": "n8n-nodes-base.if",
      "position": [
        1740,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8ccf743b-3a66-44c0-a30b-72a1d4bcf60b",
              "operator": {
                "type": "dateTime",
                "operation": "before"
              },
              "leftValue": "={{ $json.different.updatedAt.inputA }}",
              "rightValue": "={{ $json.different.updatedAt.inputB }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "fd1022a0-4f67-4603-bf94-68415776c587",
      "name": "Decode to json",
      "type": "n8n-nodes-base.set",
      "position": [
        1020,
        400
      ],
      "parameters": {
        "mode": "raw",
        "options": {},
        "jsonOutput": "={{  $json.content.base64Decode() }}"
      },
      "typeVersion": 3.4
    },
    {
      "id": "102aadd9-ace3-4fc6-a9a9-ca546362373e",
      "name": "Filter",
      "type": "n8n-nodes-base.filter",
      "position": [
        580,
        400
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "b9ed0bad-4ebe-4378-807e-1a6082c4461d",
              "operator": {
                "type": "string",
                "operation": "notContains"
              },
              "leftValue": "={{ $json.name }}",
              "rightValue": "placeholder"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "0ddf93a8-4db3-4826-a658-8fb4aedb31ce",
      "name": "Set GitHub Details",
      "type": "n8n-nodes-base.set",
      "position": [
        -40,
        280
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "850e7497-0f2f-470e-a5a2-a85a0c12aaa2",
              "name": "github_account_name",
              "type": "string",
              "value": ""
            },
            {
              "id": "5c2be15a-cb93-4fe4-a512-03a1880b8713",
              "name": "github_repo_name",
              "type": "string",
              "value": ""
            },
            {
              "id": "f4f1f0c3-7a89-427c-942f-d0e74ba4583f",
              "name": "repo_workflows_path",
              "type": "string",
              "value": ""
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "f8dfa54c-eb76-40f0-80d8-18cdab254091",
  "connections": {
    "n8n": {
      "main": [
        [
          {
            "node": "n8n vs GitHub",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter": {
      "main": [
        [
          {
            "node": "GitHub",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GitHub": {
      "main": [
        [
          {
            "node": "Decode to json",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "To base": {
      "main": [
        [
          {
            "node": "Edit for Update",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Json file": {
      "main": [
        [
          {
            "node": "To base64",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "To base64": {
      "main": [
        [
          {
            "node": "Edit for Upload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Json file1": {
      "main": [
        [
          {
            "node": "To base",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Json file1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - InputA": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code - InputB": {
      "main": [
        [
          {
            "node": "Update workflow in n8n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "n8n vs GitHub": {
      "main": [
        [
          {
            "node": "Json file",
            "type": "main",
            "index": 0
          }
        ],
        [],
        [
          {
            "node": "If n8n before GitHub",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create new workflow in n8n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Decode to json": {
      "main": [
        [
          {
            "node": "n8n vs GitHub",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Edit for Update": {
      "main": [
        [
          {
            "node": "Update file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit for Upload": {
      "main": [
        [
          {
            "node": "Upload file",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Set GitHub Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set GitHub Details": {
      "main": [
        [
          {
            "node": "n8n",
            "type": "main",
            "index": 0
          },
          {
            "node": "List files from repo",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If n8n before GitHub": {
      "main": [
        [
          {
            "node": "Code - InputB",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Code - InputA",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "List files from repo": {
      "main": [
        [
          {
            "node": "Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

Who is this for? This template is ideal for n8n administrators, automation engineers, and DevOps teams who want to maintain bidirectional synchronization between their n8n workflows and GitHub repositories. It helps teams keep their workflow backups up-to-date and ensures…

Source: https://n8n.io/workflows/5081/ — 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

Automatically back up and sync your n8n workflows to GitHub with unlimited version control. This workflow ensures your repository always reflects the latest state of your n8n instance by creating, upd

GitHub, n8n
DevOps

Backup workflows to git repository. Uses github, n8n, splitInBatches, scheduleTrigger. Scheduled trigger; 17 nodes.

GitHub, n8n
DevOps

Source code, I maintain this worflow here.

GitHub, n8n
DevOps

[bck-fluxos]. Uses github, itemLists, n8n, moveBinaryData. Scheduled trigger; 16 nodes.

GitHub, Item Lists, n8n +1
DevOps

This workflow provides a robust solution for automatically backing up all your n8n workflows to a designated GitHub repository on a daily basis. By leveraging the n8n API and GitHub API, it ensures yo

n8n, GitHub