Automation

Google Apps Script Quotas & Limits 2026

Marc SeanJuly 2, 20267 min read

This is a complete map of the limits, which ones matter for multi-tab financial models, and what you can actually do about them.

The Complete Quota Table

There are two categories: per-execution limits that kill individual script runs, and daily quotas that accumulate across your workflow.

Per-execution limits (script terminates with no recovery):

LimitConsumer (Gmail)Google Workspace
Max execution time6 minutes6 minutes
Custom function timeout30 seconds30 seconds
Simultaneous executions3030

Daily quotas (reset midnight Pacific):

LimitConsumer (Gmail)Google Workspace
Total daily runtime90 minutes6 hours
Email recipients1001,500
URL Fetch calls20,000100,000
Triggers per script2020
Properties Service read/write50,00050,000

Source: Google Apps Script quotas documentation, verified July 2026.

The Workspace numbers are dramatically better for email volume and URL Fetch. The 6-minute execution cap is identical across both tiers. You can't pay to extend it.

The 6-Minute Wall: How FP&A Models Hit It

The execution limit isn't a problem for simple scripts. It becomes a problem when you're running the kind of automation FP&A actually needs: reading actuals from a P&L tab, cross-referencing against budget, calculating variances across 36 months, writing flags to a reporting tab, then emailing a summary.

A script doing all of that on a 500-row model with getValue() called per cell is making thousands of individual API calls. That's how you blow past 6 minutes before the email step even runs.

According to Google's Apps Script quotas documentation: "If a script exceeds a quota or limitation, it is terminated and an error is displayed." The specific error is Exceeded maximum execution time. Any writes that completed before termination persist; everything else is silently lost.

Cell-by-cell iteration is the main culprit. Switching to batch reads cuts execution time by roughly 95% on large ranges.

// ❌ Cell-by-cell: ~1,000 API calls on a 500-row P&L, easily 3+ minutes
function slowVarianceCalc() {
  var plSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('P&L');
  for (var row = 2; row <= 501; row++) {
    var actual = plSheet.getRange(row, 3).getValue();   // 1 call per row
    var budget = plSheet.getRange(row, 4).getValue();   // another call
    // 1,000 round-trips to the Sheets API before you've touched results
  }
}

// âś… Batched: 2 API calls total, runs in under 2 seconds
function fastVarianceCalc() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  // Read the full actuals + budget range in a single call
  var data = ss.getSheetByName('P&L').getRange('C2:D501').getValues();
  // Process in memory - no quota cost
  var variances = data.map(function(row) {
    return [row[1] !== 0 ? (row[0] - row[1]) / row[1] : 0]; // (actual - budget) / budget
  });
  // Write all 500 variance results in a single call
  ss.getSheetByName('Variance Analysis').getRange('E2:E501').setValues(variances);
}

The same pattern applies across tabs. Reading 'P&L'!C2:D501 and 'Assumptions'!B3:B14 as two batch calls is almost always fast enough. The 6-minute wall becomes relevant only when you're doing things no batching can fix - external API calls that each take seconds, or computation that's genuinely heavy.

Custom Function Limits: 30 Seconds, Not 6 Minutes

This one trips up finance teams more than the main execution limit, because the behavior is less obvious.

Custom functions - the ones called from cells like =MYWACC(Assumptions!B3:B10) - time out after 30 seconds, not 6 minutes. They're also sandboxed: they can't write to cells outside their return value, can't send email, and can't call services requiring user authorization.

For simple calculations this is fine. The problem is when someone builds a custom function that's doing more than math: pulling from five different tabs, making conditional lookups against a 2,000-row transaction ledger, applying multi-step logic before returning a single number. Any of that can push a custom function past 30 seconds, and the cell just shows Error.

The fix is architectural: if your custom function does anything beyond arithmetic on its input arguments, convert it to a regular function triggered by a button or a time-based trigger. You get the full 6-minute budget, access to all Sheets services, and the ability to write anywhere in the workbook.

Daily Runtime: Where Workspace Earns the Difference

90 minutes/day sounds like a lot until you're running hourly triggers. A script that pulls actuals from a connected data source and refreshes a =SUMIFS('P&L'!C:C, 'P&L'!B:B, ">=" & Assumptions!$B$3) style rolling P&L might take 2-3 minutes per run. At hourly frequency, you're burning 48-72 minutes of daily runtime and leaving very little margin for additional automation.

Workspace accounts get 6 hours (360 minutes) of daily runtime. For teams running real production automation - daily actuals refresh, automated weekly commentary, scheduled sensitivity sweeps - that headroom is the meaningful upgrade.

The trigger quota (20 per script) is the same for both tiers. If you've spread automation across many independent triggers to handle different model sections, you can hit that ceiling before you hit the runtime cap.

Trigger Scheduling: What "Hourly" Actually Means

Apps Script time-based triggers support intervals down to 1 minute, but they don't fire with precision. A trigger set to "every hour" can fire anywhere within that hour window. If a board pack email needs to land at 6:00am, triggering at 5:00am and building in buffer is the right call - not triggering at 5:55am and hoping.

Sub-minute scheduling isn't possible. If your runway sensitivity model needs to refresh every 30 seconds based on a live feed, Apps Script isn't the right tool for that job.

The Practical Ceiling for Apps Script in Financial Models

Based on the quota structure, Apps Script handles these financial automation scenarios well:

  • Models up to ~2,000 rows across 8-10 tabs with batched reads
  • Hourly or less-frequent refresh cycles
  • Email distribution lists under 1,500 recipients (Workspace) or 100 (consumer)
  • Up to 20 distinct monitoring or refresh triggers per model

It starts breaking down on: 5,000+ row transaction ledgers with complex allocation logic, 15-tab LBO models with cross-tab SUMIFS-equivalent calculations that need to run every 10 minutes, or anything requiring real-time responsiveness.

For heavier workflows, the execution environment becomes the bottleneck rather than the underlying logic. ModelMonkey handles Sheets operations server-side - outside Apps Script's execution context entirely - which means the 6-minute wall and 30-second custom function limit don't apply to it. Worth knowing if your automation keeps running into those ceilings.

The limits that matter for FP&A automation in 2026:

  • 6 minutes is the absolute execution ceiling, identical for consumer and Workspace accounts
  • 30 seconds is the custom function timeout - significantly lower than most analysts expect
  • 90 minutes/day total runtime on consumer accounts is easy to exhaust with hourly triggers
  • 20 triggers per script is a real constraint for complex multi-job monitoring setups
  • Batch your reads and writes - getValues() on a 500-row range instead of 500 getValue() calls cuts execution time by ~95% and is the single highest-leverage optimization available

Workspace matters for email volume and URL Fetch calls. For execution time, everyone's working under the same ceiling.


Frequently Asked Questions