> For the complete documentation index, see [llms.txt](https://docs.ilert.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ilert.com/on-call-management-and-escalations/on-call-schedules/recurring-schedules.md).

# Recurring schedules

Build a recurring on-call schedule from layers of users that take turns on a fixed cycle, optionally limited to certain hours or to your support hours.

A recurring schedule passes on-call duty through a list of people on a fixed cycle, for example to the next person every Monday at 09:00. You set it up once, and it keeps producing shifts. For coverage that follows no pattern, use a [static schedule](/on-call-management-and-escalations/on-call-schedules/static-schedules.md) instead.

Each rotation lives in a **layer**. A simple schedule has one layer. Combine several layers for setups such as follow-the-sun or separate weekend coverage; see [Combine layers](#schedule-layers).

You can't turn a recurring schedule into a static one later, or the other way around.

## Create a recurring schedule

To describe the schedule in a chat instead of filling in the form, see [Create schedules using ilert AI](/on-call-management-and-escalations/on-call-schedules/recurring-schedules/using-ilert-ai-for-schedule-generation.md).

{% stepper %}
{% step %}

### Open the editor

Go to **On-call schedules** and click **Create schedule**. On **Create new on-call schedule**, click **Continue** on the **Recurring schedule** card.
{% endstep %}

{% step %}

### Name the schedule

Fill in **Name**, which must be unique in your account, and **Timezone**. All layers use the schedule's timezone, and it can't be changed after the schedule is created. Optionally choose up to 15 owning **Teams**.
{% endstep %}

{% step %}

### Add users

Add people with **Add user ...**. They take turns in the order listed. Drag a name to move it, and click its **×** to remove it.

To give someone more shifts than the others, add them more than once. Clicking **×** removes every copy of that person.

Stakeholders aren't offered. Viewers are, but ilert refuses to save a schedule that includes one.
{% endstep %}

{% step %}

### Set the rotation

**Rotate every** sets how long each shift lasts before the next person takes over: 1 to 54 **hour(s)**, **day(s)** or **week(s)**. It starts as 1 week. Any other number shows **Period must be a number between 1 and 54** when you leave the field, and isn't used.

**Starts on** sets when the first shift starts, and so the handover time for every shift after it. It starts as today at 08:00. **Shift handover** below the field shows the result. The weekday appears only when the rotation is a whole number of weeks.

A **Starts on** date in the past is allowed. It sets the rhythm of the rotation, but ilert creates no shifts before the moment you save.
{% endstep %}

{% step %}

### Set the coverage

By default, the layer covers **24 hours a day, 7 days a week**. To limit it, see [Limit the hours a layer covers](#limit-the-hours-a-layer-covers).
{% endstep %}

{% step %}

### Check the preview and save

The timeline at the bottom shows a row for each layer and a **Final schedule** row with the combined result. Use its arrows to move through time, and its magnifier buttons to zoom. Then click **Save**.
{% endstep %}
{% endstepper %}

ilert returns to **On-call schedules**, where the new schedule's row shows who is on call now and who is next. A schedule does nothing on its own. It pages people only once an [escalation policy](/on-call-management-and-escalations/escalation-policies.md) uses it.

## Limit the hours a layer covers

Choose one of the options under **Set on-call coverage**:

| Option                                       | The layer covers                                                                                                      |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| **24 hours a day, 7 days a week**            | All the time. This is the default.                                                                                    |
| **Only on specific times of the day**        | The same hours every day, for example 18:00 to 08:00.                                                                 |
| **Only on specific times of the week**       | Windows from one day and time to another, for example Friday 17:00 to Monday 09:00.                                   |
| **Follow support hours (respects holidays)** | The weekly hours and holidays of a support hour. See [Follow support hours](#follow-support-hours-respects-holidays). |

When you choose one of the two **Only on specific times** options, a dialog opens for the time windows:

* Each row is one window. Enter times as `HH:MM`, or ilert shows **Time format must be HH:MM**. A window can run past midnight.
* **+ Add interval** adds a row, and the minus icon removes one. A window that starts and ends at the same time is ignored.
* **Save** keeps the windows, and **Discard** drops your changes. To change the windows later, click **Edit coverage**.

Time outside a layer's windows is a gap, unless another layer covers it. When an alert escalates to a schedule while nobody is on call, ilert moves straight on to the next level of the escalation policy. See [What happens if there is a gap in a schedule?](/on-call-management-and-escalations/on-call-schedules.md#what-happens-if-there-is-a-gap-in-a-schedule)

### Follow support hours (respects holidays)

A layer can take its coverage from a [support hour](/alerting/configure-alerting/support-hours.md) instead of windows of its own. Choose **Follow support hours (respects holidays)** and select the support hour. The layer then copies:

* the support hour's **weekly hours**, as the times it covers, and
* its **holiday exceptions**. On a day without support, nobody from this layer is on call. On a day with extra support, the layer covers the extra hours.

The support hour and the schedule stay in sync. When someone changes the support hour, ilert updates every schedule that follows it from that moment on. Shifts that have already happened never change. One support hour can be followed by at most 200 schedules.

When the support hour has holiday exceptions, the timeline gets a **Holidays** row with a bar for each one, labeled with its name. Hover over a bar to see whether it removes or adds coverage, for example "Christmas Day (no coverage)". Hover over the row's label to see the support hour's name and weekly hours, with a link to open it.

{% hint style="warning" %}
**Check the timezones.** ilert applies the support hour's times as they are, in the schedule's timezone, without converting them. A support hour of 09:00 to 17:00 in Europe/London makes a New York schedule cover 09:00 to 17:00 New York time. Use a support hour in the same timezone as the schedule.
{% endhint %}

A support hour without weekly hours covers nothing except its extra-support days, so the layer is otherwise empty and nobody from it is on call.

Following support hours needs a plan that includes support hours. On other plans, the option shows a lock with **Available on a higher plan**. Choosing it shows an upgrade prompt, and the schedule can't be saved.

## Combine layers <a href="#schedule-layers" id="schedule-layers"></a>

Click **Add schedule layer** to add a layer below the existing ones. A schedule can have up to 52 layers that haven't ended, and their rotations can add up to at most 1,134 days. Each layer has its own users, rotation and coverage, and these controls:

| Control                                            | What it does                                                                                                          |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| Pencil next to the layer title                     | Names the layer. The title then reads, for example, **Layer 1: Primary rotation**.                                    |
| **End this layer** (stop icon)                     | Opens a dialog to set **Layer ends on**. The layer creates no shifts after that time.                                 |
| **Clone layer**                                    | Adds a copy of the layer at the bottom, named "Copy of" and the original name.                                        |
| **Delete this layer**                              | Ends the layer now. A layer that hasn't started yet disappears. One that has started stays in the schedule's history. |
| **Move this layer up** or **Move this layer down** | Changes the order. Appears once a schedule has two or more layers.                                                    |

<figure><img src="https://3394882078-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M76ygPnS4HUcFSX8ulm%2Fuploads%2Fgit-blob-1ef976728419173ef33c19e1aa50a74b85aaf4d6%2Frecurring-schedule-layer.png?alt=media" alt="Editing the Acme Payments weekly rotation, timezone Europe/Berlin, owned by the Acme Payments team. Its only layer, Layer 1: Primary rotation, lists Helena Guzman, Humza Vega, Greta Müller and Ali Kim under Add users. Set on-call rotation shows Rotate every 1 week(s) and Changes effective on 17/08/2026, 09:00, with Shift handover: Mon 09:00 below it. Set on-call coverage has 24 hours a day, 7 days a week selected. The layer&#x27;s header has a pencil on the left and three icons on the right, and Add schedule layer and Learn more sit below the layer."><figcaption><p>A layer of an existing schedule. When you create a schedule, the date field reads <strong>Starts on</strong> instead of <strong>Changes effective on</strong>.</p></figcaption></figure>

### Which layer wins

Where two layers both have someone on call, **the lower layer wins**. Where the lower layer has a gap, the shift from the layer above shows through. Overrides beat every layer.

For example, layer 1 rotates a team through whole weeks, and layer 2, below it, covers only Friday 17:00 to Monday 09:00 with different people. The final schedule has the layer 1 person on call on weekdays and the layer 2 person on weekends.

The **Final schedule** row in the timeline shows this combined result, without overrides. To see how the schedule lines up with others, click **Compare with other schedule**, pick schedules and click **Compare**. Each appears as an extra row below **Final schedule**, also without overrides.

### Example: follow the sun

A US team covers the day and an EU team the night, in a schedule with the timezone America/Los\_Angeles:

| Layer   | Users            | Rotate every | Starts on       | Coverage                                              |
| ------- | ---------------- | ------------ | --------------- | ----------------------------------------------------- |
| US team | The US engineers | 1 week(s)    | A Monday, 09:00 | **Only on specific times of the day**, 09:00 to 21:00 |
| EU team | The EU engineers | 1 week(s)    | A Monday, 21:00 | **Only on specific times of the day**, 21:00 to 09:00 |

All times are in the schedule's timezone. 21:00 in Los Angeles is 06:00 the next morning in Berlin for most of the year. The two layers never overlap, so their order doesn't matter.

### Example: weekdays and weekends

One group is on call from Monday morning to Friday afternoon, and another over the weekend, in a schedule with the timezone Europe/Berlin:

| Layer    | Users             | Rotate every | Starts on       | Coverage                                                             |
| -------- | ----------------- | ------------ | --------------- | -------------------------------------------------------------------- |
| Weekdays | The weekday group | 1 week(s)    | A Monday, 09:00 | **Only on specific times of the week**, Monday 09:00 to Friday 17:00 |
| Weekends | The weekend group | 1 week(s)    | A Friday, 17:00 | **Only on specific times of the week**, Friday 17:00 to Monday 09:00 |

Each layer starts when its first window opens, so a handover never falls in the middle of someone's shift.

## Change a recurring schedule

For a one-off change, such as covering a sick colleague for a day, add an [override](/on-call-management-and-escalations/on-call-schedules.md#overrides) instead. Edit the schedule when the rotation itself changes, such as when someone joins or leaves it.

Open the schedule and click **Edit**. The editor works as it does for a new schedule, with these differences:

* **Timezone** can't be changed. To use another timezone, create a new schedule.
* Existing layers show **Changes effective on** in place of **Starts on**. The field is filled in with the layer's original start date. Set it to when your changes should apply.
* The editor has no **Generate schedule with ilert AI** button.

When you save, ilert keeps the past as it was and applies the layers as they are now from the **Changes effective on** time onward. It does this for every layer, whether you changed it or not.

* **If that time has already passed**, the change applies from the moment you save, but the rotation still counts from the date in the field. Reordering people can therefore change who is on call right away.
* **If it is in the future**, the rotation starts over at that time, with the first person in the list.

To switch from one setup to another at a known time, you can also end a layer and start a new one:

{% stepper %}
{% step %}

### End the old layer

On the old layer, click **End this layer**, set **Layer ends on**, and click **End layer**. The layer then shows **This layer ends on**, followed by the date, with an **Edit** link. To undo, click **Do not end this layer**.
{% endstep %}

{% step %}

### Add the new layer

Click **Add schedule layer**, and set its **Starts on** to the time the old layer ends.
{% endstep %}

{% step %}

### Save

Before you click **Save**, check in the timeline that the new layer's shifts start where the old layer's end.
{% endstep %}
{% endstepper %}

Each save keeps the previous version of every layer. Once a schedule has 200 old layer versions, the editor shows a warning, and the next save archives the oldest 100. Archiving doesn't change future shifts or on-call reports.

## When saving fails

| Message                                                                                          | Fix                                      |
| ------------------------------------------------------------------------------------------------ | ---------------------------------------- |
| **Name: Validation Error: Value is required.**                                                   | Enter a name.                            |
| **This name is already in use. Please choose another one.**                                      | Choose a name no other schedule uses.    |
| A user **is a Stakeholder or Viewer and must not be added to a shift.**                          | Remove that user, or change their role.  |
| **Select a support hour, or choose a different coverage option.**                                | Select the support hour to follow.       |
| **Support hours are not included in your plan. Choose a different coverage option, or upgrade.** | Choose another coverage option.          |
| **You have reached the ownership boundary limit of 15 for this entity.**                         | Remove teams until at most 15 remain.    |
| **This schedule has reached the maximum amount of open layers (52)** …                           | End or delete layers you no longer need. |
| **Combined Rotation periods must not exceed 1134 days** …                                        | Shorten rotations or use fewer layers.   |

A layer without users saves without an error, but it covers nothing. Once your account has as many schedules as its plan allows, **Create recurring schedule** shows **You have reached the maximum number of schedules that you can create within your plan.** instead of the form.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ilert.com/on-call-management-and-escalations/on-call-schedules/recurring-schedules.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
