◉GEMINI LABJP
●3.8 FLASH — 3.7 Flash was deprecated on Oct 8. Requests to the old model are routed to 3.8 Flash automatically●NANO 2.1 — gemini-nano-banana-2.1 is GA. gemini-3.1-flash-image is deprecated with no shutdown date yet●DEADLINE — veo-3.1 previews and gemini-omni-flash-preview shut down Oct 22; the Deep Research agent follows Oct 23 (12-13 days left)●Q&A — Users report Gemini CLI marks a subagent run as a success even after it stops at MAX_TURNS●TTS/LIVE — 2.5-era audio and TTS previews shut down Nov 17, 38 days left●NEW — Deprecated with no shutdown date? Re-pick your image-model target with three conditions●3.8 FLASH — 3.7 Flash was deprecated on Oct 8. Requests to the old model are routed to 3.8 Flash automatically●NANO 2.1 — gemini-nano-banana-2.1 is GA. gemini-3.1-flash-image is deprecated with no shutdown date yet●DEADLINE — veo-3.1 previews and gemini-omni-flash-preview shut down Oct 22; the Deep Research agent follows Oct 23 (12-13 days left)●Q&A — Users report Gemini CLI marks a subagent run as a success even after it stops at MAX_TURNS●TTS/LIVE — 2.5-era audio and TTS previews shut down Nov 17, 38 days left●NEW — Deprecated with no shutdown date? Re-pick your image-model target with three conditions
Articles/Workspace
◧ Workspace/2026-06-16Advanced

Processing Thousands of Sheet Rows with Gemini from Apps Script — Beating the 6-Minute Limit with Chunking and Idempotency

How to stop Apps Script batch jobs from dying at the 6-minute limit: trigger-based continuation, a status-column idempotency design, and exponential backoff that carries thousands of rows to completion.


✦ Premium Article

I once tried to classify and summarize 2,000 app reviews sitting in a spreadsheet with Gemini in one pass, and the run was cut off at six minutes with nothing to show for it. As an indie developer running several apps, I keep reaching for Google Sheets to draft review replies or tidy up multilingual store metadata, because it's the surface I already live in. But when you write the obvious Apps Script loop, it dies the moment the row count grows. Worse, you don't know where it stopped, so rerunning re-processes from the top and double-bills the API. This article walks through the design that removes both walls at once, following code I actually run.

The six-minute cutoff is the first wall

A single Apps Script execution has a hard time limit: about six minutes on a consumer Google account, and about 30 minutes on a Google Workspace account. If you call Gemini once per row inside a loop, each row takes one to three seconds, so a free account hits the ceiling somewhere around 150–300 rows.

The tempting fix is to strip out every Utilities.sleep() and just go faster. I tried that first, and I think it's the wrong instinct. Speed doesn't remove the ceiling — double the rows and you stall again. The real fix is to stop trying to finish everything in one execution. You stop yourself inside a time budget and hand the rest to the next execution. Apps Script gives you time-based triggers precisely for this.

So the plan looks like this:

  1. Give the sheet a column that records processing state, so the data itself remembers how far you got
  2. Have each execution stop on its own before the clock runs out
  3. Just before stopping, schedule a trigger that re-invokes the same function a few seconds later, passing the baton

When those three fit together, a job of any size flows to completion, split across however many executions it needs.

The starting point is making every row idempotent

The real danger in split execution is double-processing on resume. If the dying run and the next run disagree about "how far did we get," you call Gemini twice on the same row. The most reliable guard is to write progress not into a script variable, but into the cell itself.

Concretely, add one status column next to your output column. It holds exactly three states: done, error, or empty. When you pick work, you only take rows where status is empty. Now, no matter when an execution dies, the next one naturally resumes from rows nobody has touched. Because nothing relies on script memory, even if a trigger fires twice, the row one run marked done simply drops out of the other run's candidates.

// Config: adjust to your own sheet
const CFG = {
  SHEET: 'reviews',     // target sheet name
  COL_INPUT: 1,         // input text column (A=1)
  COL_OUTPUT: 2,        // column to write Gemini's result (B=2)
  COL_STATUS: 3,        // processing-state column (C=3)
  HEADER_ROWS: 1,       // number of header rows
  TIME_BUDGET_MS: 4.5 * 60 * 1000, // bail at 4.5 min, short of the 6-min cap
  TRIGGER_DELAY_MS: 30 * 1000,     // resume 30 seconds later
};
 
// Take only "pending" rows where status is empty, top to bottom
function nextPendingRows_(sheet, limit) {
  const lastRow = sheet.getLastRow();
  if (lastRow <= CFG.HEADER_ROWS) return [];
  const n = lastRow - CFG.HEADER_ROWS;
  const status = sheet.getRange(CFG.HEADER_ROWS + 1, CFG.COL_STATUS, n, 1).getValues();
  const input = sheet.getRange(CFG.HEADER_ROWS + 1, CFG.COL_INPUT, n, 1).getValues();
  const rows = [];
  for (let i = 0; i < n && rows.length < limit; i++) {
    if (!String(status[i][0]).trim() && String(input[i][0]).trim()) {
      rows.push({ row: CFG.HEADER_ROWS + 1 + i, text: String(input[i][0]) });
    }
  }
  return rows;
}

The key is that selection keys off status, not the output column. If you decide "done" by whether the output cell is filled, a row where Gemini returned an empty string gets mistaken for pending. Holding state in a dedicated column also makes eyeballing the sheet afterward much easier.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦If your batch kept dying at the Apps Script 6-minute limit, you can now carry thousands of rows to completion via trigger continuation
✦You can swap a setup that re-processed the same rows on every rerun for a status-column idempotency design that never double-bills the API
✦You'll get copy-ready exponential backoff and per-row error isolation for row-level Gemini calls that used to stall on 429s
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $15 for lifetime access
View Membership →

Related Articles

◧ Workspace2026-10-03
Estimating a Sheets-Driven Gemini Bill Across the Year-End Price Switch with Apps Script
If you call the Gemini API from a spreadsheet, log the token counts per call and estimate the month in two columns: the intro price that ends on December 31, 2026 and the standard price from January 1, 2027. Apps Script, with real output.
◧ Workspace2026-09-22
Workspace turned third-party connectors on by default. Two screens to check before you decide
Since September 15, 2026, Gemini in Workspace connects to Asana, Salesforce and five other tools over MCP, and the setting ships on by default. Here is how I count what is actually enabled, from both the Admin console and the user side panel.
◧ Workspace2026-09-17
Gem sharing stops in three places: the order I check when a shared Gem never shows up
When a shared Gem never reaches the other person, the block sits in the Gem itself, in the Admin console, or in Drive. Here is what stops where, who can unblock it, and the order I check.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links