// Drive · Apps Script

Create a Drive folder only if it doesn't exist in Google Drive.

How to check for an existing Google Drive folder by name before creating one, so you never end up with duplicate folders from repeated script runs.

I want to create a Google Drive folder in Apps Script but only if it doesn't already exist, so repeated runs don't pile up duplicates.

The script

copy · paste · trigger
createFolderIfMissing.gs
Apps Script
// Returns an existing folder by name, or creates it if absent.
// Safe to call on every run — never produces duplicates.
function getOrCreateFolder(folderName) {
  var matches = DriveApp.getFoldersByName(folderName);
  if (matches.hasNext()) {
    return matches.next();
  }
  return DriveApp.createFolder(folderName);
}

// Example: get or create "Monthly Reports" in the root
function main() {
  var folder = getOrCreateFolder('Monthly Reports');
  Logger.log('Folder ID: ' + folder.getId());
}

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

Walkthrough

Why createFolder never deduplicates on its own

Google Drive allows multiple folders with identical names. That is not a bug — it is a documented design choice. DriveApp.createFolder does not check for an existing folder first; it creates a new one unconditionally every time you call it. Run a script twice and you have two folders named 'Monthly Reports'. Run a daily trigger for a month and you have thirty.

The first time I hit this I was building an invoice-filing script. After a week of trigger runs I found a wall of identical folders in the root. There is no built-in deduplication and no collision error to catch — the script just silently succeeds.

The correct approach is to query first. DriveApp.getFoldersByName returns a FolderIterator, not a single folder or null. You have to call hasNext() before calling next(), or the iterator throws 'DriveApp.FolderIterator object has no more elements'.

Reading the iterator pattern correctly

FolderIterator follows the same pattern as every other iterator in Apps Script: hasNext() returns a boolean, next() advances and returns the item. That means the idiomatic check is a single if (matches.hasNext()) block — you do not need a while loop unless you want to inspect all matching folders.

getFoldersByName searches only the root of My Drive by default when called on DriveApp directly. If the folder you are checking lives inside a specific parent, call parentFolder.getFoldersByName(folderName) instead. The method signature is the same; the scope changes.

One practical consequence: two folders named 'Reports' can coexist at different levels of the hierarchy, and getFoldersByName on the root will not find the nested one. Scope your search to the right parent, or you will create a duplicate at the root while the real folder sits inside a subfolder.

Scoping the check to a specific parent folder

Most real scripts do not want a root-level folder — they want a subfolder of an existing archive or project folder. The pattern extends cleanly: get the parent first, then call getFoldersByName on that parent object.

Here is the adjusted call chain: var parent = DriveApp.getFolderById(PARENT_FOLDER_ID); var matches = parent.getFoldersByName('Monthly Reports');. The rest of the logic is identical. I keep the parent folder ID as a named constant at the top of the script file rather than hardcoding it inline — it makes the ID easy to swap when testing against a staging folder.

If the parent folder might not exist either, wrap the whole thing in a recursive call to getOrCreateFolder, passing the parent's ID as the starting scope. Two levels of nesting is usually the practical limit before the script logic becomes harder to follow than the Drive hierarchy itself.

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
What happens if I call DriveApp.createFolder without checking first?
It creates a new folder unconditionally. Drive allows duplicate names, so you get a second folder with the same name and a different ID. There is no error, no warning, and no way to distinguish the two from the UI without checking creation timestamps.
Does getFoldersByName search subfolders recursively?
No. When called on DriveApp it searches the root of My Drive. When called on a Folder object it searches only the immediate children of that folder. There is no built-in recursive search; you would have to walk the tree manually.
Can I use this pattern inside a shared drive (Team Drive)?
Yes, but you need DriveApp.getSharedDriveById or access the shared drive via a known folder ID, then call getFoldersByName on that folder. The DriveApp root-level methods only see My Drive by default unless you pass the supportsAllDrives options object, which is only available via the Advanced Drive Service, not DriveApp.
Is it safe to call getOrCreateFolder from a time-based trigger that runs every minute?
Mostly. There is a narrow race window: two trigger executions could both reach the hasNext() check before either creates the folder, and both would call createFolder. In practice this is rare for low-frequency triggers, but if you need a hard guarantee you should use LockService.getScriptLock to serialize the check-and-create operation.