// Drive · Apps Script

Copy files from one Drive folder to another with Apps Script.

Use Apps Script to copy every file from one Google Drive folder into another — with a duplicate guard so re-running the script doesn't create a mess.

I need to copy all files from one Google Drive folder into another without doing it by hand, and without creating duplicates if I run the script more than once.

The script

copy · paste · trigger
copyFolderContents.gs
Apps Script
// Copy all files from SOURCE_FOLDER_ID into DEST_FOLDER_ID.
// Safe to re-run: skips files whose name already exists in the destination.
function copyFolderContents() {
  var sourceFolder = DriveApp.getFolderById('SOURCE_FOLDER_ID');
  var destFolder   = DriveApp.getFolderById('DEST_FOLDER_ID');

  var existing = {};
  var destFiles = destFolder.getFiles();
  while (destFiles.hasNext()) {
    existing[destFiles.next().getName()] = true;
  }

  var sourceFiles = sourceFolder.getFiles();
  while (sourceFiles.hasNext()) {
    var file = sourceFiles.next();
    if (!existing[file.getName()]) {
      file.makeCopy(file.getName(), destFolder);
    }
  }
}

Need a variant? Gnaw writes a custom version from one sentence — fields, triggers, edge cases handled.

Walkthrough

Where your folder IDs live

Open either folder in Google Drive and look at the URL: drive.google.com/drive/folders/1aBcDeFgHiJkLmNoPqRsTuVwXyZ. Everything after /folders/ is the folder ID. Paste that string in place of SOURCE_FOLDER_ID and DEST_FOLDER_ID in the script.

The script needs Drive scope, which Apps Script requests automatically the first time you run it. You'll see a permission dialog asking to 'See, edit, create, and delete all of your Google Drive files' — that's the standard DriveApp scope; there's no narrower one for read-plus-copy.

What makeCopy actually does (and what it doesn't)

DriveApp's file.makeCopy(name, targetFolder) creates a brand-new file with a new file ID. The original stays exactly where it is. For Docs, Sheets, and Slides this means a full content clone — not a shortcut, not a reference. For binary files (PDFs, images, zips) the bytes are duplicated verbatim.

The first time I hit a folder with 200 files, I ran the script twice by accident and ended up with 400. That's why the script pre-loads a name map from the destination before it touches anything. The guard is name-based, so if two source files share a name only the first one gets copied — an acceptable trade-off for a simple utility. If your folder has name collisions, switch the guard key to file.getId() and store copies' source IDs in a PropertiesService cache instead.

Moving a file is different: Drive has no native move via Apps Script (no file.moveTo() until the advanced Drive API). The classic workaround is targetFolder.addFile(file) followed by sourceFolder.removeFile(file). Those calls manipulate folder membership without duplicating content, so the file ID stays the same. Use that pattern if you want a move, not a copy.

Running on a schedule or against large folders

For one-time migrations, run the function directly from the Apps Script editor (Run > copyFolderContents). For recurring sync — say, a nightly copy from a shared intake folder into an archive — attach a time-driven trigger: Triggers > Add Trigger > copyFolderContents > Time-driven > Day timer.

Apps Script enforces a 6-minute execution limit on consumer accounts (30 minutes on Workspace). A folder with thousands of files will hit that wall. The standard fix is continuation tokens: store the last-processed file ID in PropertiesService, exit cleanly before the timeout, and have the trigger re-fire the function. For most people with folders under a few hundred files, the simple while loop above finishes in seconds.

Want a custom version?

Describe your sheet and the rule you want. Gnaw writes the Apps Script — fields, triggers, edge cases — in one shot.

FAQ

4 questions
Does makeCopy preserve the original file's sharing permissions?
No. The copy gets the destination folder's inherited permissions only. Any explicit share settings on the original file — specific people, link-sharing level — are not carried over. If permission parity matters, you'll need to read the original's permissions with file.getSharingAccess() and file.getSharingPermission() and re-apply them to the copy.
How do I copy subfolders recursively, not just top-level files?
The script above handles only files at the top level. For subfolders, call sourceFolder.getFolders() and iterate the same way, creating each subfolder in the destination with destFolder.createFolder(subfolder.getName()) and then recursing into it. A recursive function calling itself with the new folder pair is the cleanest shape.
Can I copy a file to a folder in a Shared Drive (Team Drive)?
Yes, but getFolderById works for Shared Drive folders without any extra flags in Apps Script — Drive automatically resolves the ID. The copy lands in that Shared Drive folder and inherits its permissions. What won't work is adding the copy back to a personal My Drive folder via addFile if it's already in a Shared Drive; Shared Drive files can only have one parent.
Why does my script ask for permission every time I run it?
It shouldn't after the first run. If it does, you're likely running it from a different Google account than the one that originally authorized it, or the script project was copied and the OAuth token doesn't follow. Re-authorize once under the correct account and subsequent runs are silent.
// one good script a week

Get a working Apps Script snippet in your inbox, weekly.