// Calendar · Apps Script

Create a recurring event in Google Calendar.

How to use createEventSeries and CalendarApp.newRecurrence() in Apps Script to create a recurring Google Calendar event with a proper end date.

I want to programmatically create a repeating event in Google Calendar from Apps Script without it running forever.

The script

copy · paste · trigger
createWeeklyStandup.gs
Apps Script
// Creates a weekly standup series every Monday, ending after 12 occurrences.
// Run once from the Apps Script editor; no trigger needed.
function createWeeklyStandup() {
  var cal = CalendarApp.getDefaultCalendar();

  var recurrence = CalendarApp.newRecurrence()
    .addWeeklyRule()
    .onlyOnWeekday(CalendarApp.Weekday.MONDAY)
    .times(12);

  var start = new Date('2026-06-16T09:00:00');
  var end   = new Date('2026-06-16T09:30:00');

  var series = cal.createEventSeries(
    'Weekly Standup',
    start,
    end,
    recurrence
  );

  Logger.log('Series created: ' + series.getId());
}

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

Walkthrough

Why createEventSeries, not createEvent

CalendarApp has two paths: createEvent makes a single event, createEventSeries makes a recurring one. They take the same title, start, and end arguments, but createEventSeries requires a fourth argument — a RecurrenceRule object built from CalendarApp.newRecurrence(). Skip that object and you have no recurrence at all.

The recurrence builder is chainable. addWeeklyRule() sets the frequency; onlyOnWeekday() narrows it to specific days; times(12) caps it at 12 occurrences. You can also use until(date) to cap by date instead of count. The critical thing to know: if you call neither times() nor until(), the series repeats indefinitely. That sounds fine until you need to clean it up — there is no bulk-delete for event series in Apps Script, so you end up deleting individual instances in a loop, which is slow and quota-burning.

The quota reality

Calendar operations count against your Apps Script daily quotas: consumer accounts get 5,000 calendar event creates per day, Workspace accounts get 10,000. A single createEventSeries call counts as one create regardless of how many occurrences the series contains, which makes series creation very cheap compared to creating individual events in a loop.

The first time I hit the quota wall, it was because I had written a loop that created each weekly instance as a standalone event rather than using createEventSeries. 52 events for a year-long series, and all 52 counted individually. Switching to createEventSeries dropped that to a single quota unit. If you are generating series for many calendars or many users (via the Advanced Calendar Service or domain-wide delegation), this distinction matters a lot.

Editing one instance versus the whole series

createEventSeries returns a CalendarEventSeries object. Calling setTitle() or setDescription() on that object updates every instance in the series. To update only one occurrence, you need to fetch it individually: cal.getEventById(id) where id is the instance's event ID, not the series ID. The series ID looks like a long alphanumeric string; instance IDs follow the pattern seriesId_YYYYMMDDTHHMMSSZ.

If you need to delete the series entirely, call series.deleteEventSeries(). That removes all past and future instances in one call. There is no equivalent for 'delete all future instances from a specific date' — for that, you fetch instances in a date range and delete them one by one, which brings the quota cost back. Design your end condition upfront with times() or until() rather than trying to surgically trim an infinite series later.

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
How do I create a recurring all-day event instead of a timed one?
Use createAllDayEventSeries instead of createEventSeries. It takes a title, a single Date (the start date), and the RecurrenceRule. There is no end Date argument because all-day events have no time component.
Can I set a recurring event on a calendar other than my default?
Yes. Use CalendarApp.getCalendarById('calendar-id@group.calendar.google.com') to get the target calendar, then call createEventSeries on that object instead of getDefaultCalendar(). The calendar ID is in the calendar's settings page in Google Calendar.
My series is creating events in the wrong time zone. How do I fix it?
The Date object you pass is interpreted in the script's time zone, which defaults to the script project's time zone set in Project Settings (not the calendar's time zone). Check Apps Script editor > Project Settings > Time zone and align it with the calendar, or construct your Date string with an explicit UTC offset.
How do I add guests to every event in the series at creation time?
createEventSeries returns a CalendarEventSeries; call addGuest('email@example.com') on it before the function returns. Guests added to the series object are applied to all instances. Adding a guest to a single fetched instance only affects that occurrence.
// one good script a week

Get a working Apps Script snippet in your inbox, weekly.