GEMINI LABJP
CLI — Gemini CLI and the Code Assist IDE extensions stop serving free, AI Pro, and Ultra users on Jun 18 (two days out), with users directed to the Antigravity CLIGA — Gemini 3.5 Flash is now generally available and, since Jun 8, enabled by default and non-removable in the Gemini Enterprise appAGENTS — Managed Agents entered public preview, letting you build and deploy stateful autonomous agents inside Google-hosted, isolated Linux sandboxesIMAGE — gemini-3.1-flash-image-preview and gemini-3-pro-image-preview shut down on Jun 25; OGP image pipelines should move to successorsPRO — Gemini 3.5 Pro, previewed at I/O on May 19, had not shipped as of Jun 15, with Jun 23 and Jun 30 seen as the likeliest release windowsAPI — The v1beta Interactions API has breaking changes, reshaping the API to support mid-flight steering and asynchronous tool callsCLI — Gemini CLI and the Code Assist IDE extensions stop serving free, AI Pro, and Ultra users on Jun 18 (two days out), with users directed to the Antigravity CLIGA — Gemini 3.5 Flash is now generally available and, since Jun 8, enabled by default and non-removable in the Gemini Enterprise appAGENTS — Managed Agents entered public preview, letting you build and deploy stateful autonomous agents inside Google-hosted, isolated Linux sandboxesIMAGE — gemini-3.1-flash-image-preview and gemini-3-pro-image-preview shut down on Jun 25; OGP image pipelines should move to successorsPRO — Gemini 3.5 Pro, previewed at I/O on May 19, had not shipped as of Jun 15, with Jun 23 and Jun 30 seen as the likeliest release windowsAPI — The v1beta Interactions API has breaking changes, reshaping the API to support mid-flight steering and asynchronous tool calls
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 $10 for lifetime access
View Membership →

Related Articles

Workspace2026-05-27
Replying to 11 Languages of Google Play Reviews With Gemini Without Sounding Like a Bot
After two major Android updates, I had to clear a backlog of unanswered Google Play reviews on Beautiful 4K/HDR Wallpapers (50M+ downloads) in Japanese, English, Traditional Chinese, Korean, Thai, Italian, Russian, Persian, Ukrainian, and Polish. This is the operations design I settled on for using Gemini as a translation and vocabulary partner without losing the human temperature.
Workspace2026-05-25
Why I Stopped Organizing Gmail and Let Gemini Recover My Memory Instead
Running six domains as an indie developer means my Gmail accounts are buried under tens of thousands of unfiled messages. Here is how I switched from asking Gemini to find emails to asking it to answer questions, with the traps I hit along the way.
Workspace2026-05-24
The Day @Canva Moved In With Gemini — A One-Week Field Note on Designing Through Conversation via the MCP Connector
Canva is now formally integrated with Google Gemini, and you can invoke `@Canva` from inside the Gemini app to generate, edit, and resize for social platforms in a single chat. Writing as the indie creator behind dolice.design, I share a week of operating notes on Brand Kit prompting and the new Magic Layers feature.
📚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
See all →