// Drive · Apps Script

List all files in a folder in Google Drive.

How to iterate over every file in a Google Drive folder using Apps Script's FileIterator — including recursive descent into subfolders.

I want to write an Apps Script that lists every file inside a Drive folder, but I'm getting only some of the files back and can't figure out why subfolders are missing.

The script

copy · paste · trigger
listFiles.gs
Apps Script
// List every file in a folder, recursing into subfolders
function listAllFiles(folderId) {
  var folder = DriveApp.getFolderById(folderId);
  var results = [];
  collectFiles(folder, results);
  Logger.log(results.join('\n'));
}

function collectFiles(folder, results) {
  var files = folder.getFiles();
  while (files.hasNext()) {
    var file = files.next();
    results.push(file.getName() + ' — ' + file.getId());
  }
  var subfolders = folder.getFolders();
  while (subfolders.hasNext()) {
    collectFiles(subfolders.next(), results);
  }
}

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

Walkthrough

getFiles returns an iterator, not an array

DriveApp.getFiles() and folder.getFiles() hand back a FileIterator — an object with two methods: hasNext() returns true while items remain, and next() advances the cursor and returns the current File. There is no length property, no index access, no forEach. The first time I hit this, I tried results = folder.getFiles().length and got undefined back; the iterator just does not work that way.

The canonical pattern is a while loop: call hasNext() as the condition, call next() inside the body. Apps Script's quota logs a single Drive API call per next() invocation, so iterating 500 files costs 500 calls against your daily Drive read quota (roughly 20,000 read operations per day on a personal account, higher on Workspace). For large folders that matters.

Why direct children only — and how recursion fixes it

folder.getFiles() returns files whose parent is exactly that folder. A file sitting inside a subfolder does not appear. I have watched this bite people who organize assets two or three levels deep and then wonder why their audit script is short by half.

To reach everything, you also call folder.getFolders() — which returns a FolderIterator with the same hasNext/next contract — and recurse into each child. The collectFiles function above does this: drain the file iterator first, then drain the folder iterator and call collectFiles again on each. Depth-first, no external stack needed. Drive's folder tree can nest up to around 20 levels in practice; Apps Script's call stack limit is well above that.

One edge case worth knowing: a single file can have multiple parents in Drive (the old "Add to My Drive" behavior). If a file lives in two folders that are both descendants of your root folder, recursion will surface it twice. Whether that matters depends on your use case — deduplicating by file ID is the straightforward fix.

Getting the folder ID from a URL

The folderId argument is the long alphanumeric string in the Drive URL: https://drive.google.com/drive/folders/1A2B3C4D5E6F — everything after the final slash. Paste that string into listAllFiles() as a quoted argument, or store it in PropertiesService if the script runs on a schedule.

If you want to target the folder the bound spreadsheet lives in, DriveApp.getFileById(SpreadsheetApp.getActiveSpreadsheet().getId()).getParents().next() returns that folder without hardcoding any ID. The .next() call is necessary because getParents() is also an iterator.

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
Why does my script only return files at the top level and miss everything in subfolders?
folder.getFiles() is scoped to direct children only. Files inside subfolders require a separate folder.getFolders() loop and a recursive call into each subfolder, as shown in the collectFiles function above.
Can I use DriveApp.searchFiles() instead of recursing?
Yes, for simple cases. DriveApp.searchFiles('"FOLDER_ID" in parents') searches only direct children. The query trashed = false and fullText contains 'keyword' searches your entire Drive regardless of folder. Neither gives you a clean subtree-scoped search without building the folder list yourself first, so recursion is usually cleaner when you need everything under a known root.
How do I include the file's MIME type or last-modified date in the output?
The File object exposes getMimeType(), getLastUpdated(), getSize(), and getUrl() among others. Swap or extend the results.push() line: file.getName() + ' ' + file.getMimeType() + ' ' + file.getLastUpdated() gives you all three in one string.
The script times out on a large folder tree. What can I do?
Apps Script hard-limits execution to 6 minutes (30 minutes on Workspace). For deep or wide trees, write intermediate results to a Sheet row-by-row inside the loop rather than accumulating them in memory, and use ContinuationTokens — FileIterator and FolderIterator both expose getContinuationToken() so you can resume in a subsequent run triggered by a time-based trigger.