This workflow follows the Google Drive → Google Drive Trigger 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "c4dca8f0-98fa-4b06-a806-1ab271f024a2",
"name": "Config",
"type": "n8n-nodes-base.set",
"position": [
120,
460
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "a916dcbd-d681-4e09-9ce9-0f50a1b4290b",
"name": "keep",
"type": "string",
"value": "=last"
},
{
"id": "949a2f76-5981-4fd2-9665-b10db26e2f48",
"name": "action",
"type": "string",
"value": "=flag"
},
{
"id": "7f4502b4-c330-4c9c-ab89-ba53874aafbb",
"name": "owner",
"type": "string",
"value": "={{ $json.owner || $json.owners[0].emailAddress }}"
},
{
"id": "592eb79e-28db-4470-8347-36b2a661cb03",
"name": "folder",
"type": "string",
"value": "={{ $json.folder || $json.parents[0]}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "2562ed4a-8ecd-4a32-ae51-bc85daa9817b",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
1800,
440
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "1d28f976-2467-4d18-8698-556d29a5f8c0",
"name": "isDuplicate",
"type": "boolean",
"value": "={{ $json.isDuplicate }}"
},
{
"id": "e9d8eb20-7668-4287-bfb4-d4f66c019f73",
"name": "id",
"type": "string",
"value": "={{ $json.id }}"
},
{
"id": "587e5f8e-bd94-4ec5-80f2-066c99922135",
"name": "name",
"type": "string",
"value": "={{ $json.name }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "e7f0482c-77c7-46a0-8a36-e61bb624c422",
"name": "Filter",
"type": "n8n-nodes-base.filter",
"position": [
2020,
440
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "bd33247c-4c88-4c0b-bdfe-6f9dca0205e3",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.isDuplicate }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "28768732-29a4-4446-8b12-dda187976bf9",
"name": "Deduplicate Keep First",
"type": "n8n-nodes-base.code",
"position": [
1580,
560
],
"parameters": {
"jsCode": "// Sort files by creation time (oldest first)\nconst sorted = items.sort((a, b) => \n new Date(a.json.createdTime) - new Date(b.json.createdTime));\n\nconst seen = {};\nfor (const item of sorted) {\n const md5 = item.json.md5Checksum;\n\n // Failsafe: Skip if md5Checksum is missing or empty\n if (!md5) {\n item.json.isDuplicate = false; // Mark as not duplicate to avoid issues\n continue; // Skip to the next item\n }\n\n item.json.isDuplicate = md5 in seen;\n if (!item.json.isDuplicate) seen[md5] = true;\n}\nreturn items;"
},
"executeOnce": false,
"typeVersion": 2
},
{
"id": "1f6f9529-2283-4806-ad5a-b0425f9f68e2",
"name": "Deduplicate Keep Last",
"type": "n8n-nodes-base.code",
"position": [
1580,
360
],
"parameters": {
"jsCode": "// Sort files by creation time (latest first)\nconst sorted = items.sort((a, b) => \n new Date(b.json.createdTime) - new Date(a.json.createdTime));\n\nconst seen = {};\nfor (const item of sorted) {\n const md5 = item.json.md5Checksum;\n\n // Failsafe: Skip if md5Checksum is missing or empty\n if (!md5) {\n item.json.isDuplicate = false; // Mark as not duplicate to avoid issues\n continue; // Skip to the next item\n }\n\n if (md5 in seen) {\n item.json.isDuplicate = true;\n } else {\n item.json.isDuplicate = false;\n seen[md5] = true;\n }\n}\nreturn items;"
},
"executeOnce": false,
"typeVersion": 2
},
{
"id": "c5250dd1-6eeb-4b89-b2e7-e44a8d88212c",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-40,
-120
],
"parameters": {
"color": 5,
"width": 440,
"height": 800,
"content": "# 2. Configuration\nChoose the **keep** and **action** behavior of the workflow\n\n1. The **keep** parameter let's you decide whether to keep the first or last received file when duplicates are detected. (possible values: `first`, `last`. Default: `last`)\n2. The **action** parameter let's you decide what to do with the detected duplicates. Send them to the trash or flag them by renaming them with prefix DUPLICATE- (possible values: `trash`, `flag`. Default: `flag`) flag already prexied by DUPLICATE- are not flagged again.\n\n\nThe parameters `owner` and `folder` are taken from the trigger and will probably never need to be changed:\n- The **folder** points to the folder to work with. By default it is taken from the trigger.\n- The **owner** parameter needs to match the owner of the files. The workflow only works with files owned by this user. It is specified with the user email and is taken from the first file owner of the trigger."
},
"typeVersion": 1
},
{
"id": "67c4d02f-b170-4504-9bae-7bf14db7abd3",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
460,
180
],
"parameters": {
"color": 7,
"width": 320,
"height": 500,
"content": "## Working Folder\nThe \"Working Folder\" node let's you choose Files to deduplicate.\n\nThis workflow includes a filter to work on just 1 folder at depth level 1. It doesn't work with files in nested folders\n\nYou can remove the Folder filter to work on the entire drive instead or add different filters."
},
"typeVersion": 1
},
{
"id": "9ed26ef0-da89-43c5-9e12-2ec97b2e51f6",
"name": "Send Duplicates to Trash",
"type": "n8n-nodes-base.googleDrive",
"position": [
2760,
320
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {},
"operation": "deleteFile"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "fcfd08fa-7a19-4974-b3bb-6ed27a2030cf",
"name": "No Operation, do nothing",
"type": "n8n-nodes-base.noOp",
"position": [
2800,
600
],
"parameters": {},
"typeVersion": 1
},
{
"id": "de7967e7-eb3b-456c-b12e-6de3165ad29a",
"name": "Is Flagged",
"type": "n8n-nodes-base.if",
"position": [
2540,
620
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c8d8eac5-e03a-4673-bcf9-a8acaa95cb8e",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $('Trash/Flag Duplicates').item.json.name }}",
"rightValue": "DUPLICATE-"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "d227d6ee-97e7-4b4d-b1a2-4cd402be99d5",
"name": "Google Drive Trigger",
"type": "n8n-nodes-base.googleDriveTrigger",
"position": [
-360,
460
],
"parameters": {
"event": "fileCreated",
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyX",
"unit": "minutes",
"value": 15
}
]
},
"triggerOn": "specificFolder",
"folderToWatch": {
"__rl": true,
"mode": "list",
"value": "1-tjf96Ooj0SL8qaE04BGIeCGnd-O1R8c",
"cachedResultUrl": "https://drive.google.com/drive/folders/1-tjf96Ooj0SL8qaE04BGIeCGnd-O1R8c",
"cachedResultName": "2025/04\n"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "22e1638e-5c2e-41bc-b66e-fcee6af05762",
"name": "Drop Google Apps files",
"type": "n8n-nodes-base.filter",
"position": [
940,
460
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1e7d9666-fba0-4fe7-b03a-1a4e5c07b389",
"operator": {
"type": "string",
"operation": "notStartsWith"
},
"leftValue": "={{ $json.mimeType }}",
"rightValue": "application/vnd.google-apps"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "ec80f4de-5dff-4693-bff4-2509fd581d70",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
840,
180
],
"parameters": {
"color": 7,
"width": 320,
"height": 500,
"content": "# Discard found Google Apps documents\nDocs, Sheets, Forms, Slides, Drawins etc. are discarded because they are not actual binary files and their content can't be directly checked."
},
"typeVersion": 1
},
{
"id": "66ee766a-3dea-449f-827c-1922c6e053f3",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-520,
-120
],
"parameters": {
"color": 5,
"width": 440,
"height": 800,
"content": "# 1. Trigger Settings and Working Folder\n\nWhen using Google Drive Trigger configure the **Poll times** and the **Folder** to work with.\n\nBy Default the trigger is configured to check for *file uploads* every 15 minutes.\n\nWhen configured with a specific folder in the drive the workflow works only with files directly in the folder (It will not check/modify files in sub-folders).\n\nWhen configured with the root (/) folder of the drive it will check all files in all folders and sub-folders so **USE THIS WITH CAUTION** since it might lead to trashing/renaming of important files. "
},
"typeVersion": 1
},
{
"id": "6f8a7855-2ee3-426d-879f-afb303d5aa20",
"name": "Working Folder",
"type": "n8n-nodes-base.googleDrive",
"position": [
560,
460
],
"parameters": {
"filter": {
"folderId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Config').item.json.folder }}"
},
"whatToSearch": "files"
},
"options": {
"fields": [
"*"
]
},
"resource": "fileFolder",
"returnAll": true,
"queryString": "='{{$('Config').item.json.owner}}' in owners",
"searchMethod": "query"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "6f69e6d3-96ca-4411-9a48-160ebdb2a273",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2500,
540
],
"parameters": {
"color": 7,
"width": 540,
"height": 220,
"content": "### Files that already start with *DUPLICATE-* are not flagged again."
},
"typeVersion": 1
},
{
"id": "65b4ba42-89ce-437c-a3e8-bf3f9b01cc21",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
2500,
780
],
"parameters": {
"color": 7,
"width": 360,
"height": 240,
"content": "### In Google Drive Trashed files are kept for 30 days before being permanently deleted. \nThey can be reviewed and restored during that 30 day interval."
},
"typeVersion": 1
},
{
"id": "99374aa8-e597-4919-8b64-c376b246621a",
"name": "Google Drive",
"type": "n8n-nodes-base.googleDrive",
"position": [
2880,
800
],
"parameters": {
"fileId": {
"__rl": true,
"mode": "id",
"value": "={{ $json.id }}"
},
"options": {},
"operation": "update",
"newUpdatedFileName": "=DUPLICATE-{{ $json.name }}"
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "6ae62c31-4cf0-48e7-aa42-19fc259c5981",
"name": "Keep First/Last",
"type": "n8n-nodes-base.switch",
"position": [
1300,
460
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "last",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "7f5ba21d-8f3d-4736-9c34-ac7ebd6a9699",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Config').item.json.keep }}",
"rightValue": "last"
}
]
},
"renameOutput": true
},
{
"outputKey": "first",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "93a013f6-6c59-47ad-bce3-8b34cc8f026c",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Config').item.json.keep }}",
"rightValue": "first"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "9cb84da7-3cd9-4a53-af09-8b63f1cf8a34",
"name": "Trash/Flag Duplicates",
"type": "n8n-nodes-base.switch",
"position": [
2240,
440
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "send to trash",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "0314ac48-e7b7-406b-abcd-8cd1ab872c79",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Config').item.json.action }}",
"rightValue": "trash"
}
]
},
"renameOutput": true
},
{
"outputKey": "flag as duplicate",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "70d8e5f1-16a6-4921-ad9c-ab00049e507d",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Config').item.json.action }}",
"rightValue": "flag"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.2
}
],
"connections": {
"Config": {
"main": [
[
{
"node": "Working Folder",
"type": "main",
"index": 0
}
]
]
},
"Filter": {
"main": [
[
{
"node": "Trash/Flag Duplicates",
"type": "main",
"index": 0
}
]
]
},
"Is Flagged": {
"main": [
[
{
"node": "No Operation, do nothing",
"type": "main",
"index": 0
}
],
[
{
"node": "Google Drive",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Filter",
"type": "main",
"index": 0
}
]
]
},
"Working Folder": {
"main": [
[
{
"node": "Drop Google Apps files",
"type": "main",
"index": 0
}
]
]
},
"Keep First/Last": {
"main": [
[
{
"node": "Deduplicate Keep Last",
"type": "main",
"index": 0
}
],
[
{
"node": "Deduplicate Keep First",
"type": "main",
"index": 0
}
]
]
},
"Google Drive Trigger": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"Deduplicate Keep Last": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Trash/Flag Duplicates": {
"main": [
[
{
"node": "Send Duplicates to Trash",
"type": "main",
"index": 0
}
],
[
{
"node": "Is Flagged",
"type": "main",
"index": 0
}
]
]
},
"Deduplicate Keep First": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"Drop Google Apps files": {
"main": [
[
{
"node": "Keep First/Last",
"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.
googleDriveOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
How this works
This workflow streamlines managing files in Google Drive by automatically detecting and handling duplicates, saving you hours of manual sorting and ensuring your storage remains organised without losing important data. It's ideal for teams or individuals who frequently upload or sync files via Google Drive and want to prevent clutter from repeated versions. The key step involves a code node that deduplicates entries, either keeping the first or last occurrence, before routing duplicates to the trash for easy review.
Use this workflow when your Google Drive accumulates duplicates from shared folders or automated uploads, such as during project collaborations or backups. Avoid it for tiny drives with minimal activity, as the setup overhead might not justify the benefits; instead, opt for manual checks. Common variations include modifying the filter to target specific file types like images or documents, or integrating additional notifications for duplicate alerts.
About this workflow
Code Filter. Uses stickyNote, googleDrive, noOp, googleDriveTrigger. Event-driven trigger; 20 nodes.
Source: https://github.com/Zie619/n8n-workflows — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Purpose: Automate the process of finding and managing duplicate files in your Google Drive.
Remove Advanced Background from Google Drive Images. Uses httpRequest, splitOut, googleDrive, editImage. Event-driven trigger; 16 nodes.
Create Custom Presentations per Lead. Uses googleDrive, googleSheets, googleDriveTrigger, googleSlides. Event-driven trigger; 14 nodes.
Important: This workflow uses the Autype community node and requires a self-hosted n8n instance.
Automatically signs PDF documents the moment they land in a Google Drive folder — no manual steps needed. The signed output is routed to a Drive folder. Google Drive Trigger watches a folder every min