AutomationFlowsGeneral › Recursive Google Drive Folder Duplicator with Permission Preservation

Recursive Google Drive Folder Duplicator with Permission Preservation

ByAnnie To @annieth on n8n.io

This n8n workflow creates a complete recursive copy of any Google Drive folder, preserving the entire folder structure, all files, and sharing permissions. Duplicates folders with unlimited nested subfolders Copies all files maintaining original names and metadata Preserves…

Manual trigger★★★★☆ complexity22 nodesGoogle Drive
General Trigger: Manual Nodes: 22 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #7402 — 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "4a36d370-4d43-4090-a8e0-6e2002550bfc",
      "name": "Set Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        -1328,
        7968
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "sourceFolderId",
              "value": "1RdenWIrighEr6S53e25CkwYmUa7jAFjq"
            },
            {
              "name": "targetFolderId",
              "value": "13BQRVwg2QFGFRJstRzUt0CoO5w8bpS1I"
            },
            {
              "name": "newFolderName",
              "value": "Duplicated Folder"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "4107d258-363c-4bf9-b5bf-3cfa2a8e7f8e",
      "name": "Create Main Folder",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -1168,
        7968
      ],
      "parameters": {
        "name": "={{ $json.newFolderName }}",
        "driveId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.targetFolderId }}"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        },
        "resource": "folder"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "5b2cdf23-9f31-4668-a5cc-0dd2d6b94129",
      "name": "Start Recursive Processing",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        -1008,
        7968
      ],
      "parameters": {
        "options": {},
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "{{ $workflow.id }}"
        },
        "workflowInputs": {
          "value": {
            "sourceFolderId": "={{ $node['Set Configuration'].json.sourceFolderId }}",
            "targetFolderId": "={{ $json.id }}"
          },
          "schema": [
            {
              "id": "sourceFolderId",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "sourceFolderId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "targetFolderId",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "targetFolderId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "59abdaa3-b57e-4c75-a07e-1b8e720fb5ac",
      "name": "Main Completion",
      "type": "n8n-nodes-base.set",
      "position": [
        -848,
        7968
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "status",
              "value": "Main folder duplication completed successfully"
            },
            {
              "name": "sourceFolder",
              "value": "={{ $node['Set Configuration'].json.sourceFolderId }}"
            },
            {
              "name": "newMainFolder",
              "value": "={{ $node['Create Main Folder'].json.id }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "62d4d9eb-7c1d-48c8-bf0b-55269ee4caeb",
      "name": "Prepare File Data",
      "type": "n8n-nodes-base.set",
      "position": [
        -864,
        8448
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "originalFileId",
              "value": "={{ $node['Filter Files Only1'].json.id }}"
            },
            {
              "name": "originalPermissions",
              "value": "={{ JSON.stringify($node['Filter Files Only1'].json.permissions || []) }}"
            },
            {
              "name": "newFileId",
              "value": "={{ $json.id }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "27f8d8ca-96ab-41e8-96db-33afdbd63959",
      "name": "Recursive Call to Self",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        -160,
        8656
      ],
      "parameters": {
        "options": {},
        "workflowId": {
          "__rl": true,
          "mode": "id",
          "value": "{{ $workflow.id }}"
        },
        "workflowInputs": {
          "value": {
            "sourceFolderId": "={{ $json.originalFolderId }}",
            "targetFolderId": "={{ $json.newFolderId }}"
          },
          "schema": [
            {
              "id": "sourceFolderId",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "sourceFolderId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "targetFolderId",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "targetFolderId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "15343d75-5c61-4de7-9ce4-4250ceccc03d",
      "name": "Level Completion",
      "type": "n8n-nodes-base.set",
      "position": [
        64,
        8464
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "status",
              "value": "Level processing completed"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "0221146d-05a2-4c8f-a812-8b7ebe3e6a1c",
      "name": "Search Folder Contents1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -1344,
        8544
      ],
      "parameters": {
        "filter": {},
        "options": {
          "fields": [
            "id",
            "name",
            "mimeType",
            "permissions"
          ]
        },
        "resource": "fileFolder",
        "returnAll": true,
        "queryString": "'{{ $json.sourceFolderId }}' in parents and trashed = false",
        "searchMethod": "query"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "b437a057-3931-4c8e-ab6b-fab0f9f117dc",
      "name": "Filter Files Only1",
      "type": "n8n-nodes-base.filter",
      "position": [
        -1184,
        8448
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.mimeType }}",
              "value2": "application/vnd.google-apps.folder",
              "operation": "notEqual"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ce118b58-cd56-4eaf-adea-e2e117eec17e",
      "name": "Filter Folders Only1",
      "type": "n8n-nodes-base.filter",
      "position": [
        -1184,
        8640
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.mimeType }}",
              "value2": "application/vnd.google-apps.folder"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4b80da29-fc25-48db-8aed-0f8c5ef13526",
      "name": "Copy File1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -1024,
        8448
      ],
      "parameters": {
        "name": "={{ $json.name }}",
        "fileId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        },
        "driveId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $node['Start'].json.targetFolderId }}"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        },
        "operation": "copy",
        "sameFolder": false
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "38835c99-1d5c-4571-a505-ac3a57db699b",
      "name": "Check File Has Permissions1",
      "type": "n8n-nodes-base.if",
      "position": [
        -704,
        8448
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ JSON.parse($json.originalPermissions || '[]').length }}",
              "value2": "0",
              "operation": "larger"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "9c25ddac-17de-45c9-b106-e13e740f8385",
      "name": "Prepare File Permissions1",
      "type": "n8n-nodes-base.code",
      "position": [
        -512,
        8272
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst newFileId = data.newFileId;\nconst originalPermissions = JSON.parse(data.originalPermissions || '[]');\nconst permissionsToApply = [];\nif (originalPermissions.length > 0) {\n  for (const permission of originalPermissions) {\n    if (permission.role !== 'owner' && permission.type && permission.role) {\n      const permObj = {\n        fileId: newFileId,\n        type: permission.type,\n        role: permission.role\n      };\n      if (permission.type === 'user' || permission.type === 'group') {\n        if (permission.emailAddress) {\n          permObj.emailAddress = permission.emailAddress;\n        }\n      } else if (permission.type === 'domain') {\n        if (permission.domain) {\n          permObj.domain = permission.domain;\n        }\n      }\n      permissionsToApply.push(permObj);\n    }\n  }\n}\nif (permissionsToApply.length > 0) {\n  return permissionsToApply.map(p => ({ json: p }));\n} else {\n  return [];\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "b2927eae-9f20-49ab-a60b-8fc5e6784cdb",
      "name": "Apply File Permission1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -352,
        8272
      ],
      "parameters": {
        "fileId": "={{ $json.fileId }}",
        "options": {
          "sendNotificationEmail": false
        },
        "operation": "share",
        "permissionsUi": {
          "permissionsValues": {}
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "bc443b2f-cc4b-4474-a78c-1d2ec1e4f500",
      "name": "Create Subfolder1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -1024,
        8640
      ],
      "parameters": {
        "name": "={{ $json.name }}",
        "driveId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $node['Start'].json.targetFolderId }}"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        },
        "resource": "folder"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "01063a74-b9a6-4378-95b3-4dce49690f6f",
      "name": "Prepare Folder Data1",
      "type": "n8n-nodes-base.set",
      "position": [
        -864,
        8640
      ],
      "parameters": {
        "values": {
          "string": [
            {
              "name": "originalFolderId",
              "value": "={{ $node['Filter Folders Only1'].json.id }}"
            },
            {
              "name": "originalPermissions",
              "value": "={{ JSON.stringify($node['Filter Folders Only1'].json.permissions || []) }}"
            },
            {
              "name": "newFolderId",
              "value": "={{ $json.id }}"
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 1
    },
    {
      "id": "d223bee5-58d6-4f38-8eab-9ec0a4101a08",
      "name": "Check Folder Has Permissions1",
      "type": "n8n-nodes-base.if",
      "position": [
        -704,
        8640
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ JSON.parse($json.originalPermissions || '[]').length }}",
              "value2": "0",
              "operation": "larger"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e840b153-3754-4fb2-88b9-97a4e675e05c",
      "name": "Prepare Folder Permissions1",
      "type": "n8n-nodes-base.code",
      "position": [
        -512,
        8544
      ],
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst newFolderId = data.newFolderId;\nconst originalPermissions = JSON.parse(data.originalPermissions || '[]');\nconst permissionsToApply = [];\nif (originalPermissions.length > 0) {\n  for (const permission of originalPermissions) {\n    if (permission.role !== 'owner' && permission.type && permission.role) {\n      const permObj = {\n        fileId: newFolderId,\n        type: permission.type,\n        role: permission.role\n      };\n      if (permission.type === 'user' || permission.type === 'group') {\n        if (permission.emailAddress) {\n          permObj.emailAddress = permission.emailAddress;\n        }\n      } else if (permission.type === 'domain') {\n        if (permission.domain) {\n          permObj.domain = permission.domain;\n        }\n      }\n      permissionsToApply.push(permObj);\n    }\n  }\n}\nif (permissionsToApply.length > 0) {\n  return permissionsToApply.map(p => ({ json: p }));\n} else {\n  return [];\n}"
      },
      "typeVersion": 2
    },
    {
      "id": "f4a0f68a-947a-4f57-b3fd-18a5d819592b",
      "name": "Apply Folder Permission1",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        -352,
        8544
      ],
      "parameters": {
        "fileId": "={{ $json.fileId }}",
        "options": {
          "sendNotificationEmail": false
        },
        "operation": "share",
        "permissionsUi": {
          "permissionsValues": {}
        }
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "c3779818-366b-4a85-9422-8c72d4da956f",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1856,
        7664
      ],
      "parameters": {
        "color": 3,
        "width": 368,
        "height": 1200,
        "content": "# Google Drive Folder Duplicator with Permissions\n\n## This workflow creates a complete duplicate of any Google Drive folder\nIncluding:\n- All files and subfolders (recursive)\n- Preserving folder structure\n- Copying sharing permissions\n- Maintaining file metadata\n\n## Use Cases\n- Backup folder structures\n- Template duplication\n- Project archiving\n- Permission-preserved migrations\n\n## Setup Requirements\n\n***1. Google Drive Credentials:***\n* OAuth2 API connection required\n* https://www.googleapis.com/auth/drive\n\n***2. Folder IDs:***\n- Source folder ID (to duplicate)\n- Target parent folder ID (destination)\n\n***3. Permissions:***\n- Read access to source folder\n- Write access to target folder\n- Admin rights for permission copying"
      },
      "typeVersion": 1
    },
    {
      "id": "0720dc37-20be-486e-9e7e-6086927013d1",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1472,
        7664
      ],
      "parameters": {
        "width": 1792,
        "height": 480,
        "content": "## START HERE\n\nConfiguration Hub\n\nThis node sets up the workflow parameters:\n- Source folder to duplicate\n- Target destination folder\n- New folder name\n\nEdit these values before running the workflow."
      },
      "typeVersion": 1
    },
    {
      "id": "6fbd5544-e61b-4cfd-a982-271eed9f45db",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1472,
        8160
      ],
      "parameters": {
        "width": 1792,
        "height": 704,
        "content": "## CORE RECURSIVE ENGINE\n\n1. SCAN: Discovers all folder contents (files + subfolders)\n2. SPLIT: Separates files from folders \n3. COPY: Duplicates files with permissions\n4. CREATE: Makes subfolders with permissions\n5. RECURSE: Calls itself for each subfolder\n\n***UNLIMITED DEPTH RECURSION***\nThe workflow calls itself for every subfolder found, creating an infinite loop that processes ALL nested levels automatically."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Copy File1": {
      "main": [
        [
          {
            "node": "Prepare File Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Subfolder1": {
      "main": [
        [
          {
            "node": "Prepare Folder Data1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare File Data": {
      "main": [
        [
          {
            "node": "Check File Has Permissions1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Configuration": {
      "main": [
        [
          {
            "node": "Create Main Folder",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Main Folder": {
      "main": [
        [
          {
            "node": "Start Recursive Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Files Only1": {
      "main": [
        [
          {
            "node": "Copy File1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Folders Only1": {
      "main": [
        [
          {
            "node": "Create Subfolder1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Folder Data1": {
      "main": [
        [
          {
            "node": "Check Folder Has Permissions1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apply File Permission1": {
      "main": [
        [
          {
            "node": "Level Completion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Recursive Call to Self": {
      "main": [
        [
          {
            "node": "Level Completion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Folder Contents1": {
      "main": [
        [
          {
            "node": "Filter Files Only1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Filter Folders Only1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Apply Folder Permission1": {
      "main": [
        [
          {
            "node": "Recursive Call to Self",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare File Permissions1": {
      "main": [
        [
          {
            "node": "Apply File Permission1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Start Recursive Processing": {
      "main": [
        [
          {
            "node": "Main Completion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check File Has Permissions1": {
      "main": [
        [
          {
            "node": "Prepare File Permissions1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Level Completion",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Folder Permissions1": {
      "main": [
        [
          {
            "node": "Apply Folder Permission1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Folder Has Permissions1": {
      "main": [
        [
          {
            "node": "Prepare Folder Permissions1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Recursive Call to Self",
            "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 n8n workflow creates a complete recursive copy of any Google Drive folder, preserving the entire folder structure, all files, and sharing permissions. Duplicates folders with unlimited nested subfolders Copies all files maintaining original names and metadata Preserves…

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

More General workflows → · Browse all categories →

Related workflows

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

General

26 個 n8n 初學者小技巧,加速 5x 開發時間|🧠 省力知識庫. Manual trigger; 34 nodes.

General

Workflow 2469. Uses moveBinaryData, googleDrive, itemLists, n8n. Scheduled trigger; 33 nodes.

Move Binary Data, Google Drive, Item Lists +1
General

NextCloud:NextCloud:Folder:create move copy delete list:File:upload move copy download delete. Uses start, nextCloud, readBinaryFile. Manual trigger; 28 nodes.

Start, Next Cloud, Read Binary File
General

Transporeon - orders - step 3 - process single. Uses start, functionItem, httpRequest, microsoftSql. Manual trigger; 26 nodes.

Start, Function Item, HTTP Request +3
General

AI ImgGen. Uses manualTrigger, stickyNote, convertToFile, splitInBatches. Event-driven trigger; 21 nodes.

HTTP Request, Google Sheets, Google Drive