Skip to content
// Drive · Sheets · Apps Script

Convert Excel files to Google Sheets in Google Drive.

How to convert .xlsx files in Google Drive to native Google Sheets format using Apps Script and the Drive advanced service, without manual re-upload.

I have .xlsx files sitting in Drive and I want to convert them to Google Sheets format programmatically so I can run scripts against them without wrestling with import dialogs every time.

The script

copy · paste · trigger
convertExcelToSheets.gs
Apps Script
// Convert every .xlsx in a folder to native Google Sheets format
// Requires: Resources > Advanced Google Services > Drive API (v2) enabled

function convertExcelFilesInFolder() {
  var folderId = 'YOUR_FOLDER_ID_HERE';
  var folder = DriveApp.getFolderById(folderId);
  var files = folder.getFilesByType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');

  while (files.hasNext()) {
    var file = files.next();
    var resource = {
      title: file.getName().replace('.xlsx', ''),
      mimeType: 'application/vnd.google-apps.spreadsheet',
      parents: [{ id: folderId }]
    };
    Drive.Files.copy(resource, file.getId());
    Logger.log('Converted: ' + file.getName());
  }
}

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

Walkthrough

Why DriveApp alone won't do it

DriveApp is the default Drive service in Apps Script and it handles most file operations well. Copying a file, renaming it, moving it between folders — all fine. What it cannot do is change a file's MIME type during a copy. If you call DriveApp.getFileById(id).makeCopy(), you get an exact byte-copy of the .xlsx, still an Excel file, still wearing the green Sheets icon as a lie.

The conversion happens at the Drive API layer, specifically the Files.copy method in Drive API v2, which accepts a resource object where you can set mimeType to application/vnd.google-apps.spreadsheet. That signals to Drive's server-side conversion pipeline to parse the Excel binary and produce a real Sheets file. The advanced Drive service exposes this directly; the built-in DriveApp wrapper does not.

Enabling the advanced service before you run anything

In the script editor, open Extensions > Apps Script (or Resources > Advanced Google Services if you're on the legacy editor). Find Drive API in the list and toggle it on. You also need the corresponding Google Cloud project to have the Drive API enabled — the dialog links you there directly. Skip this step and you'll get a ReferenceError: Drive is not defined the first time you call Drive.Files.copy.

The first time I hit this, I assumed DriveApp and the Drive advanced service were the same thing. They are not. DriveApp is a simplified wrapper; Drive (capital D, the advanced service) is a thin client over the actual REST API. You need both enabled: the advanced service toggle in the script editor, and the API itself in the Cloud Console. One without the other gives you a different error each time, which is annoying to diagnose.

What the copy operation produces and what it leaves behind

Drive.Files.copy does not delete the original. After the script runs, your folder contains both the original .xlsx and a new native Sheets file with the same name minus the extension. That is intentional — Drive has no atomic convert-in-place operation. If you want to clean up the originals afterward, call DriveApp.getFileById(file.getId()).setTrashed(true) inside the same loop, after the copy call.

The converted Sheets file preserves formulas, cell values, named ranges, and basic formatting. Pivot tables backed by Excel's data model, slicers, and some conditional-formatting rules that use Excel-specific functions will either convert imperfectly or drop silently. For reporting sheets with standard SUM/VLOOKUP/INDEX logic, the output is clean. For heavy Excel workbooks with Power Query or VBA, run the conversion and then visually spot-check the output before trashing the source.

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 this work on .xls files, not just .xlsx?
Yes. Swap the MIME type in getFilesByType to application/vnd.ms-excel and the Drive.Files.copy call handles the rest. The conversion path for .xls (Excel 97-2003 format) goes through the same server-side pipeline.
Can I run this against all .xlsx files in My Drive, not a specific folder?
Use DriveApp.searchFiles('mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"') instead of folder.getFilesByType. This returns every .xlsx your account can see, including files shared with you. Make sure you handle the parents array carefully — you probably want to place converted files in the same folder as each source, not a hardcoded destination.
The script times out before finishing. How do I handle large batches?
Apps Script has a 6-minute execution limit. For large folders, add a ContinuationToken: save files.getContinuationToken() to PropertiesService before the timeout and resume from it on the next trigger run. Google's documentation for FileIterator covers the exact API; it is the standard pattern for batch Drive operations.
After conversion, the Sheets file shows a strikethrough or unrecognized formula. What happened?
Excel-only functions like IFERROR with certain argument counts, FORECAST.ETS, or dynamic array functions (FILTER, SORT) may not have Sheets equivalents. The cell keeps the formula text but shows an error. You have to substitute a Sheets-compatible formula manually. The conversion does not silently drop the cell — it converts what it can and flags the rest, so it's easier to audit than you might expect.
// one good script a week

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