---
title: "Schedule preventive maintenance"
description: "Preventive maintenance in IoTFlows is a recurrence rule on a work order, not an object of its own. The Recurrence picker sits in the create modal and in the work-order drawer, anchors every pattern to the work order's due date, and takes an interval, a weekday set, an end date, and the timezone the rule is read in. A rule authored in the planner's timezone rather than the plant's lands on the wrong shift every time it fires."
category: "Scheduled work"
source_url: "https://www.iotflows.com/docs/maintain/preventive-maintenance/"
---
# Schedule preventive maintenance

Make a maintenance job repeat on a fixed calendar, and make it land on the right shift.

**Before you start.** You need a work order with a due date, from [Create a maintenance work order](/docs/maintain/create-a-work-order/#due-date). Set your organization timezone first, in [Shifts and timezone](/docs/admin/shifts-and-timezone/#timezone), so a rule can be pinned to the plant instead of to whoever wrote it.

## 1. There is no separate PM object
A *recurrence* is a rule stored on a work order that says when the job comes back: a pattern, an interval, and an optional end. Each date the rule produces is an *occurrence*. The work order's due date is the first one, and every later occurrence is counted from it.

A *PM*, a preventive maintenance job, is that rule and nothing else. There is no PM record, no PM list and no PM permission: a quarterly gearbox inspection is a work order carrying `Monthly on the first Tuesday`.

That is the payoff, because anything you can do to a work order you can do to a PM: reassign it, attach the last technician's photograph, change its parts, export it. See [Update, discuss, and close a work order](/docs/maintain/work-order-detail/).

One path cannot make a PM. A request raised from the **Maintenance** panel in the job runner is submitted with its recurrence fields empty, so nobody creates a schedule by accident from the floor. See [Submit a maintenance request](/docs/maintain/submit-a-request/#job-runner).

> **Info:**
> **Should this be a recurrence at all?**
>
> You do not need recurrence for a job that repeats irregularly. A filter change that is due every 500 spindle hours falls on a different date every month, and a calendar rule either replaces it too early or lets it run too long.
>
> Use a meter instead, so the trigger is runtime rather than the calendar: [Trigger maintenance from meter readings](/docs/maintain/meters/).

## 2. Add a recurrence rule
The same picker appears in two places.

**In the create modal**, from the board at `/<organization>/maintenance`:

1. Set a due date on the **Due Date** chip. This is the first occurrence.
2. Select the **Recurrence** chip.
3. Pick a pattern, or **Custom** for anything the list does not cover.
4. Create the work order. The chip reads **Recurring** until you do.

Selecting **Recurrence** before there is a due date raises **Set a due date first**, because the series has nothing to count from.

**In the work-order drawer**, on a work order that already exists:

1. Open the work order from the board. The URL gains `?selected_wo=`.
2. In **Properties**, select the **Recurrence** row. It reads **Add recurrence** while the work order has no rule.
3. Pick a pattern, then select **Save**. This row is the one exception to the drawer's save-on-change behavior.

The two pickers hold the same controls under shorter labels in the drawer: **End Recurrence** is **Ends** there, and **Time Zone** is **Timezone**. The field names below are the create modal's.

![The create modal's recurrence panel with Recurrence Pattern set to Custom, a Recurrence Frequency control reading Weekly, a row of round day pills with Mon highlighted, and a Repeat every field reading 1 week, with numbered callouts on the pattern control, the weekday row and the interval field](/images/maintain/mnt-pm-02.webp)

*The Recurrence picker with a weekly pattern being set, showing the pattern control (1), the weekday row (2), and the interval (3). A work order carrying one of these is a preventive maintenance schedule; there is no separate PM object.*

## 3. Daily, weekly, monthly, annual
The pattern list is built from the due date, so its wording changes with the date you picked. A work order due Tuesday, October 6, 2026 offers these.

| Pattern | Example rule | Next occurrences |
|---|---|---|
| Daily | `Daily` | Oct 7, Oct 8, Oct 9 |
| Weekdays only | `Every Weekday (Monday to Friday)` | Oct 7, Oct 8, Oct 9 |
| Weekly | `Weekly on Tuesday` | Oct 13, Oct 20, Oct 27 |
| Monthly, by weekday | `Monthly on the first Tuesday` | Nov 3, Dec 1, Jan 5 |
| Annual | `Annually on October 6` | Oct 6 2027, Oct 6 2028, Oct 6 2029 |

Monthly patterns repeat by weekday, not by date. A due date that is the last Tuesday of its month also offers `Monthly on the last Tuesday`, which is what you want for a job that has to happen before a month closes rather than on the 27th.

The picker previews **Next 3 occurrences** under the list so you can check a rule before saving it. The preview covers the daily, weekday, weekly and annual patterns; several of the monthly ones show none, so read the rule's own wording there.

> **Warning:**
> **The create modal names the wrong weekday**
>
> The table above is what the drawer's picker offers. The create modal's picker reads the due date a calendar day early: give a new work order a due date of Tuesday, October 6 and it offers `Weekly on Monday`, `Monthly on the first Monday` and `Annually on October 5`, and preselects the `Mon` pill. The recurrence panel shown above is in exactly that state.
>
> The offset is in the picker's wording, not in the date you set — the **Due Date** chip still reads `Oct 6`. Set the pattern in the drawer after the work order exists, or check the rule on the work order once it is saved.

## 4. Intervals
Every preset runs at an interval of one. To run a job every second week or every third month, pick **Custom**, set **Frequency**, then set **Repeat every** to the number you want. A rule set to `Weekly, repeat every 6 weeks` on a Tuesday lands on Oct 6, Nov 17 and Dec 29.

Daily has no interval field in either picker. A rule that skips days is a weekly rule with the right days selected, not a daily rule with an interval.

## 5. Weekday sets
A custom weekly rule carries a row of day pills, and it can land on more than one day. Select `Mon`, `Wed` and `Fri` and one rule covers a three-times-a-week greasing round, rather than three work orders that drift apart the first time somebody edits one.

The pill for the due date's own weekday is selected when the panel opens — in the create modal, the pill for the day before it, as [Daily, weekly, monthly, annual](#patterns) describes. Keep at least one selected, or the rule has no day to land on. The pills are inert on the daily, monthly and yearly frequencies.

## 6. End date
**End Recurrence** is **Never** until you change it. Set it to **On a Specific Date** and a date and a time appear, already filled in: thirteen weeks past the due date, at 9:00 AM. That is a default, not a reading of your due time — a work order due at 8:00 AM still ends at 9:00. Change both to the date and time the series should stop. The calendar will not offer a date before the due date, and the time is a dropdown of half hours.

![A cropped detail of the recurrence panel's end section, with End Recurrence set to On a Specific Date, a date button reading 1/5/2027 beside a time dropdown reading 9:00 AM, and a clear cross to the right of them](/images/maintain/mnt-pm-04.webp)

*The end-date field in the recurrence panel with a date and a time set. An end date stops the recurrence, and a rule that produced no next occurrence usually hit this.*

Give a rule an end date when the work has a horizon: a warranty inspection for the first year, a weekly check while a machine is on watch after a rebuild. Leave it at **Never** for standing maintenance, and stop it by hand when the machine is retired.

A recurring work order that stopped producing a next occurrence has almost always hit its end date. Open the rule and read the date before looking anywhere else.

> **Warning:**
> **Why did a count-limited rule not stop?**
>
> The third option, **After Number of Occurrences**, does not reach the server. The work order saves with the pattern and no end, so the rule keeps going past the count you typed.
>
> To stop a series after a fixed number of jobs, use **On a Specific Date** and set it to the date of the last occurrence you want.

## 7. Choose the timezone
The date and time you type are read as wall-clock time in the timezone you select, then stored in UTC. **Time Zone** offers **Local Timezone**, the browser's own zone, **Organization Timezone**, the one set in [Shifts and timezone](/docs/admin/shifts-and-timezone/#timezone), and **Custom Timezone**, any zone from the list. It is one setting covering both the due time and the end date, but it is easy to miss, because neither picker shows it until something else is set. In the create modal it appears at the bottom of the custom recurrence panel only once **End Recurrence** is **On a Specific Date**; in the drawer it sits in the **Due Date** dialog, labelled with the zone it currently resolves to rather than the word Timezone. Select that label to open the choice.

**Set this to the plant's timezone, not the planner's.** A weekly PM authored from a different timezone lands on the wrong shift, and it does it every week without anyone noticing which week it started. Choose **Organization Timezone** for a single-site organization, and **Custom Timezone** when you are planning work for a plant in a region other than your own.

![A cropped detail of the recurrence panel showing the Time Zone label, a highlighted select reading Local Timezone, and the zone's full name, GMT minus 04:00 Eastern Time US and Canada, to the right of the control](/images/maintain/mnt-pm-03.webp)

*The Time Zone selector in the recurrence panel, set to Local Timezone, with the zone it resolves to shown beside it. Its three choices are Local Timezone, Organization Timezone, and Custom Timezone. Set this to the plant's timezone, not the planner's.*

A planner in Detroit writing an 8:00 AM Tuesday PM for a plant in Phoenix, with **Local Timezone** left alone, stores it at 12:00 UTC. That is 5:00 AM in Phoenix, three hours before first shift. It is worse than a constant error: Phoenix does not observe daylight saving, so the same rule slips to 6:00 AM in November and back again in March.

*How a recurrence rule generates occurrences, and what happens when the rule's timezone is not the plant's.*

## 8. Edit a recurring work order
A recurring work order edits like any other. **Properties** shows the live rule in its **Recurrence** row, written out as a sentence, for example `Repeats every week on Tuesday until 12/22/2026`. Select the row to change it: the panel opens on the current rule, and **Save** writes the new one.

Changing the due date moves the whole series, because the pattern is anchored to it. Move a Tuesday PM to Wednesday and every future occurrence moves with it. A failed date change reads **Issues updating due date**, and the value in the drawer reverts.

A work order with no due date can still be given a rule from the drawer. Saving one sets the due date to today at the work order's due time, or 9:00 AM if it has none, so check the date afterwards rather than assuming the series starts next week.

## 9. Stop a recurrence
To end a series and keep the work order, open the **Recurrence** row, pick **Does not repeat**, and select **Save**. The rule is cleared and the work order stays where it is, with its history, comments and attachments intact.

In the create modal, **Clear** in the top right of the recurrence dropdown does the same before the work order exists. Clearing the due date also drops the rule, because the series has nothing left to anchor to.

Deleting the work order is the wrong way to stop a PM. It takes the machine's maintenance history with it, which is the record the next person needs when the same bearing fails again.

## Recurrence fields
| Field | Values | Required | Effect |
|---|---|---|---|
| **Recurrence Pattern** | `Does not repeat`, `Daily`, `Weekly on <weekday>`, `Every Weekday (Monday to Friday)`, the monthly patterns the due date allows, `Annually on <date>`, `Custom` | Yes | Sets the frequency, and for a preset the interval and weekday set behind it |
| **Frequency** | `Daily`, `Weekly`, `Monthly`, `Yearly` | In **Custom** only | The unit the interval counts in |
| **Repeat every** | A whole number, 1 or more | No, defaults to 1 | How many of that unit between occurrences. Not offered for daily |
| Day pills | Any set of the seven weekdays | Weekly only | Which days a weekly rule lands on |
| **End Recurrence** | `Never`, `On a Specific Date`, `After Number of Occurrences` | No, defaults to `Never` | What stops the rule. Only a date is stored |
| End date and time | A date on or after the due date, a time on the half hour | Only when the end is a date | The last moment the rule can produce an occurrence |
| **Time Zone** | `Local Timezone`, `Organization Timezone`, `Custom Timezone` | No, defaults to `Local Timezone` | The zone the due time and the end date are read in before they are stored as UTC |

The saved rule is shown as a sentence on the work order, in the **Recurrence** column of the board's Table view, on the card in every other view when that field is switched on, and in the CSV export. Turning the column on and off is in [Organize work on the maintenance board](/docs/maintain/maintenance-board/#density).

## See also
- [Trigger maintenance from meter readings](/docs/maintain/meters/). Runtime and cycle counts as the trigger, instead of the calendar.
- [Shifts and timezone](/docs/admin/shifts-and-timezone/#timezone). Set the organization timezone a rule can be pinned to.
- [Create a maintenance work order](/docs/maintain/create-a-work-order/#recurrence). Every other field a work order carries.
- [Organize work on the maintenance board](/docs/maintain/maintenance-board/). Find recurring work in the calendar and table views.
- [Work order fields and statuses](/docs/maintain/work-order-fields/). Every field, status and export column, in one table.
