Skip to content

Basics

Google Apps Script quotas and limits

Google caps how long one run may take and how much your scripts may do in a day. Knowing the caps changes how you write anything that touches a lot of rows.

1 of 8

What a quota is

A quota is a cap Google puts on how much your scripts may do. There are two kinds. A limit applies to one run, such as the six minutes a single execution may take. A daily quota applies to everything your scripts do in a day, such as the number of email recipients.

Quotas are counted per Google account, not per script. Five scripts sending email from the same account share one daily email allowance between them.

Nothing is charged and nothing breaks for good. When you go over, that run stops with an error. Daily quota windows reset about 24 hours after the first request that used that quota, not 24 hours after you exhaust it.

2 of 8

A personal account and a work account get different numbers

A consumer account is a free address ending in gmail.com. A Google Workspace account is one your employer or your school pays for, usually at your own domain.

Workspace accounts get much larger daily quotas. Email is where people notice first: 100 recipients a day on a consumer account against 1,500 on Workspace, at the time of writing.

What counts is the account that owns the run. A trigger runs as the person who created it, so a script running on a colleague trigger spends that colleague quota, not yours.

3 of 8

The numbers, at the time of writing

Google changes these from time to time, so treat the list as a guide and check the official page before you build something that depends on an exact number. It is at https://developers.google.com/apps-script/guides/services/quotas and it shows the consumer and the Workspace figures side by side.

  • Script runtime: 6 minutes for one execution.
  • Custom function runtime: 30 seconds for one call from a cell.
  • Triggers total runtime: 90 minutes a day on a consumer account and 6 hours a day on Google Workspace.
  • Email recipients a day: 100 on a consumer account, 1,500 on Google Workspace.
  • URL Fetch calls a day: 20,000 on a consumer account, 100,000 on Google Workspace.
  • Properties reads and writes a day: 50,000 on a consumer account, 500,000 on Google Workspace.
  • Triggers: 20 per user per script.
  • Simultaneous executions: 30 per user.

4 of 8

The six minute limit

One execution gets six minutes at the time of writing. Past that, Apps Script stops it and records "Exceeded maximum execution time". Everything already written to the sheet or already sent stays done, so a run stopped halfway leaves half the job finished.

A custom function typed into a cell gets 30 seconds, which is far less, because a sheet can call hundreds of them at once. All of your triggers together get 90 minutes a day on a consumer account or 6 hours on Google Workspace, so a five-minute job cannot run every hour around the clock on a consumer account but can fit within the Workspace runtime allowance.

The usual first fix is doing less work per row.

5 of 8

Reading in bulk protects you from more than slowness

Every call to a Google service is a round trip from the script to Google servers and back. A loop that calls getValue() once per cell across a thousand rows makes a thousand round trips, and that on its own can use the whole six minutes.

One getValues() call reads those thousand rows in a single trip. One setValues() writes the answers back in one more. The same script then finishes in seconds and leaves your quotas alone.

The idea carries over to the other services. Search Gmail once and loop over the results. Fetch one web address that returns many records instead of one address per record.

6 of 8

Split a long job into batches

When there is more work than six minutes allows, do part of it per run and remember where you stopped. PropertiesService gives you a small store of text that survives between runs, so it can hold a resume-from-row marker. You can see what is stored under Project Settings, in the Script Properties table.

The loop below watches the clock. Once four minutes have gone by it stops early, saves the row number to start from next time, and returns. A time driven trigger calls the function again later, it reads the marker, and it carries on where it left off.

Stop well before the limit. Four minutes leaves room for a slow last row and for the writing at the end. When the marker passes the last row, the function clears it so the next run starts fresh.

Do four minutes of work, then save where to continue
function processCustomersInBatches() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Customers');
  if (!sheet) throw new Error('Add a Sheet tab named Customers before running this function.');

  const properties = PropertiesService.getScriptProperties();
  const firstDataRow = 2;
  const startRow = Number(properties.getProperty('nextRowToProcess') || firstDataRow);
  const lastRow = sheet.getLastRow();
  if (startRow > lastRow) {
    properties.deleteProperty('nextRowToProcess');
    Logger.log('Every row is done. The next run starts again from row ' + firstDataRow + '.');
    return;
  }

  const values = sheet.getRange(startRow, 1, lastRow - startRow + 1, 2).getValues();
  const stopAfterMilliseconds = 4 * 60 * 1000;
  const startedAt = Date.now();

  let index = 0;
  while (index < values.length) {
    const [name] = values[index];
    Logger.log('Handling row ' + (startRow + index) + ': ' + name);
    index += 1;
    if (Date.now() - startedAt > stopAfterMilliseconds) break;
  }

  const nextRow = startRow + index;
  properties.setProperty('nextRowToProcess', String(nextRow));
  Logger.log('Handled ' + index + ' rows. The next run starts at row ' + nextRow + '.');
}

7 of 8

How a limit looks in Executions

Open the left sidebar of the editor and click Executions, the icon that looks like a list with a clock. Every run of every function is listed there with its status, when it started, and how long it took.

A run that hit the six minute limit shows Timed out. A run stopped by a quota shows Failed, and opening the row shows the message. "Exceeded maximum execution time" is the six minute limit. "Service invoked too many times for one day" is a daily quota, and the word after the colon names which one.

The duration column is your early warning. A run that has crept up to four or five minutes will start failing as soon as there is a little more data.

8 of 8

What to do when you hit a limit

Most scripts that run out of time are doing a small amount of real work with far too many service calls around it.

  • Wait for the reset. A daily quota window clears about 24 hours after its first request, not after it filled up, and there is no way to buy more or to clear it early.
  • Do less per run. Send to fewer recipients, or handle a few hundred rows rather than all of them.
  • Split the work across runs with a saved marker, as in the batch example above.
  • Cut the round trips. One getValues() and one setValues() in place of a call per cell.
  • Mark finished rows with a status column, so a second run does not repeat work that already cost you quota.
  • Check which account is running it. A Workspace account has far more headroom than a personal one for the same script.

Remember

The short version

  • One run gets 6 minutes, a custom function gets 30 seconds, and all triggers together get 90 minutes a day on a consumer account or 6 hours on Google Workspace, at the time of writing.
  • A free Gmail account may email 100 recipients a day and a Google Workspace account 1,500, counted per account rather than per script.
  • A trigger spends the quota of whoever created it, not the quota of whoever is watching.
  • One getValues() and one setValues() beat a call per cell, and that alone keeps most runs inside the time limit.
  • Check the current figures on the Apps Script quotas page before you rely on any of them.

Keep going

Put it to work

All basics