// Apps Script

Switch an old script from Rhino to the V8 runtime.

One line in appsscript.json enables V8, but any Rhino-only syntax anywhere in the project kills every function and trigger. Here is how to migrate safely and roll back in thirty seconds if something breaks.

I want to enable the V8 runtime on an existing Apps Script project so I can use modern JavaScript, but I am worried about breaking things that are already working.

The script

copy · paste · trigger
appsscript.json
Apps Script
// appsscript.json — set runtimeVersion to enable V8
// Rollback: change V8 back to DEPRECATED_ES5
{
  "timeZone": "America/New_York",
  "dependencies": {},
  "exceptionLogging": "STACKDRIVER",
  "runtimeVersion": "V8"
}

// Code.gs — safe V8-compatible replacement for a common Rhino pattern
// Rhino allowed: for each (var item in collection) {}
// V8 requires standard for...of instead
function listSheetNames() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var names = [];
  var sheets = ss.getSheets();
  for (var i = 0; i < sheets.length; i++) {
    names.push(sheets[i].getName());
  }
  Logger.log(names.join(', '));
}

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

Walkthrough

The one-line change and why it is a project-wide bomb

Open the Apps Script editor, click Project Settings (the gear icon), and check "Show appsscript.json manifest file in editor." Then open that file and change `"runtimeVersion": "DEPRECATED_ES5"` to `"runtimeVersion": "V8"`. Save. That is the entire migration from a settings standpoint.

What catches people off guard is the failure mode. V8 parses every .gs file in the project as a unit before running anything. One Rhino-only statement — a `for each` loop, a `__iterator__` method, a `Date.prototype.getYear` call in an otherwise untouched utility file — causes a syntax or runtime error that prevents the whole script from initializing. Not just the file that contains the bad line. Every function, every trigger, the entire project goes dark.

The first time I hit this it took me twenty minutes to figure out why a completely unrelated trigger had stopped firing. The error message pointed at the Rhino syntax in a helper file I had not touched in two years. V8 does not isolate the damage; it fails at parse time, before any execution happens.

Finding Rhino-only syntax before you flip the switch

The three patterns that break most often under V8 are: `for each (var x in obj)` (a Mozilla-specific extension Rhino supported, not standard ES), XML literals like `var x = <tag/>`, and `__iterator__` or `__defineGetter__` on prototypes. Do a text search across all .gs files for those strings before you change runtimeVersion.

The Apps Script editor has no project-wide search, so either use the browser's find-in-page on each file, or copy all your .gs files into a local editor with multi-file search. Any hit needs to be rewritten: `for each` becomes a standard `for...of` or indexed `for` loop; XML literals need to be replaced with `XmlService` calls or plain strings; the prototype methods have no direct replacement and usually need a logic rewrite.

After fixing the files, change `runtimeVersion` to `V8`, save, and immediately run one function manually from the editor toolbar. If the Execution Log shows the function completing, your triggers are also alive. If you see a red syntax error, V8 caught something the search missed — read the error, fix the line, repeat.

Instant rollback while you keep fixing files

If production triggers are firing and you need to un-break them immediately, set `"runtimeVersion": "DEPRECATED_ES5"` in appsscript.json and save. Rhino resumes within seconds. You do not need to revert any .gs file changes you already made — DEPRECATED_ES5 tolerates both old and new syntax.

This lets you migrate file by file. Fix one .gs file, flip to V8, test, flip back to DEPRECATED_ES5, fix the next file. Tedious for large projects, but it keeps triggers running throughout. Once every file passes a V8 test run, leave runtimeVersion set to V8 permanently.

One practical note: the `DEPRECATED_ES5` value is exactly that — deprecated. Google has not announced a hard removal date as of mid-2026, but they have signaled V8 is the intended path. Old scripts will keep running on Rhino for now, but new V8-only APIs (like `globalThis` or native `Promise` support in triggers) are not back-ported, so staying on Rhino indefinitely means foregoing those.

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
After I set runtimeVersion to V8, all my triggers stopped running with no error in the dashboard. What happened?
A parse-time error in any .gs file silently kills initialization. Open the editor, run any function manually, and look at the Execution Log — it will show the actual syntax error and the file name. Fix that line, then triggers resume automatically without redeployment.
Can I use arrow functions and const/let after switching to V8?
Yes. V8 supports ES2019 and most ES2020 syntax: arrow functions, const/let, destructuring, spread, async/await, optional chaining, and nullish coalescing. The one thing that does not work the same way is top-level await — Apps Script still requires async functions to be called from a synchronous trigger wrapper.
My script uses XmlService and it works fine on Rhino. Will it break on V8?
XmlService itself is a Google service and is runtime-agnostic — it works on both. What breaks under V8 is E4X, the old Rhino XML literal syntax (angle-bracket XML directly in JavaScript code). If your script uses XmlService.parse() and XmlService.getContentType() style calls rather than inline XML literals, it will migrate without changes.
Is there a way to see which runtime a deployed script is currently using without opening the manifest?
Not from outside the editor. You have to open the project, enable manifest display in Project Settings, and read appsscript.json. The Apps Script API (the REST API for managing scripts) does expose the runtimeVersion field in the project Content resource if you need to audit it programmatically across many projects.