---
title: Set and change a refresh schedule
description: Pick a cadence and an anchor time for a dashboard, understand when a run actually fires, and know what happens after a failed run.
updated: 2026-09-11
tier: pro
---

A published dashboard re-runs its own SQL on the cadence you set, with no AI in
the loop. This page is how to set that cadence, change it, and read what happens
afterwards.

:::warning{title="Any non-manual cadence needs a paid plan"}
Arming an automatic schedule is refused on a free plan with
`a paid plan is required to schedule automatic refresh`. See
[what is gated](/concepts/plans-and-gating#what-is-gated).

Setting a schedule **back to manual is always allowed**, on any plan.
:::

## Two places to set it

| Where | What it can set |
|---|---|
| The **Schedules** page at [dashies.ai/app/schedules](https://dashies.ai/app/schedules) | Everything |
| Your AI tool, via `set_refresh_schedule` | Everything |

Your AI can also set the coarse cadence at publish time, in the spec's
`source.schedule`. That takes `manual`, `hourly`, `daily`, `weekly`, or
`monthly`, and you refine the exact timing afterwards.

## Cadences, intervals, and anchors

| Cadence | Interval allowed | Anchor |
|---|---|---|
| `manual` | none | none. It runs only when triggered. |
| `hourly` | every 1, 2, 3, 4, 6, 8, or 12 hours | optional hour, which then needs a time zone |
| `daily` | every 1 to 30 days | optional hour and time zone |
| `weekly` | every 1 to 4 weeks | day of week, hour, and time zone: all three or none |
| `monthly` | every 1 to 12 months | day of month, hour, and time zone: all three or none |

The model behind this table is in
[cadences and intervals](/concepts/schedules#cadences-and-intervals).

Anchor values:

- **Hour** is 0 to 23.
- **Day of week** is 0 to 6, with **0 meaning Sunday**.
- **Day of month** is **1 to 28**.
- **Time zone** must be a real IANA zone name, such as `America/New_York`.

Three of those constraints surprise people, so here is why each exists:

- **Hourly takes only divisors of 24.** "Every 5 hours" is rejected, because a
  non-divisor drifts across the daily hour grid instead of repeating cleanly.
- **Day of month stops at 28.** If you could ask for the 31st, February would
  silently skip. The clamp guarantees every month has the day you picked.
- **Hourly is the floor.** There is no cadence below it to ask for.

## When a run actually fires

The displayed next run is the **nominal** time. Runs are claimed on a grid, and
each dashboard carries a small fixed offset so that thousands of dashboards
sharing an `09:00` anchor do not all fire in the same instant.

The practical consequence, worth knowing before you file a bug:

- An anchored schedule fires within roughly **30 minutes** of its nominal time.
- A dashboard sitting slightly past its displayed next run is normal, not late.

The offset is never shown, because it is not a property of your schedule. See
[the precision you actually get](/concepts/schedules#the-precision-you-actually-get).

## Daylight saving

An anchored schedule keeps its **local** wall-clock time across a transition.
`Daily 09:00 America/New_York` stays `09:00` local; it does not drift to `08:00`
or `10:00`.

On the transition day itself, the real gap between two daily runs is 23 or 25
hours. A wall time that does not exist in spring, or happens twice in autumn, is
normalized rather than lost or doubled. The next-run time the app shows and the
time the run actually fires agree across the boundary.

An unanchored hourly schedule is unaffected, because it is an absolute
instant. The policy in full:
[daylight saving](/concepts/schedules#daylight-saving), and
[anchors and time zones](/concepts/schedules#anchors-and-timezones).

## Running one now

The Schedules page has a **Run now** control on every dashboard.

:::note{title="Refreshing a workspace dashboard from your AI needs a seat"}
Because a refresh rewrites the dashboard's data, it takes the same permission as
republishing it, so a view-only member is refused:

```bash
You hold a view-only role in this workspace, so you cannot publish, change or refresh its dashboards. A workspace admin can change your role.
```

**Run now** in the web app applies exactly the same rule, though it words the
refusal differently (`your role in this workspace is view-only`) because it
answers a browser rather than an AI tool.
:::

:::warning{title="On-demand refresh needs a paid plan, and the workspace is the payer"}
The payer is the workspace the dashboard lives in, whatever plan you happen to
hold yourself:

```json
{ "ok": false, "error": "Refreshing on demand requires a paid plan on this workspace. Only a workspace admin can change the plan.", "code": "tier_required" }
```

If you hit the second one, the plan has to go on **this** workspace, and only a workspace
admin can put it there. A plan on another workspace you belong to does not clear it.
:::

Repeat triggers within 60 seconds of a previous attempt short-circuit and report
back that they were coalesced, **unless the last attempt failed**. A pipeline
retrying seconds after a failure genuinely re-runs, because the data is still
stale.

## After a failed run

A failed run does not strand a dashboard, and it does not retry at full rate
either.

- Retries back off at **5 minutes, then 10, 20, 40, 80**, doubling until they cap
  at one full period of that dashboard's own cadence. A permanently broken daily
  dashboard retries about once a day rather than 96 times.
- On the next success, the failure count resets and the schedule re-anchors
  normally.
- In the UI a failing schedule reads **Retrying** with the actual retry time,
  rather than a red Failed sitting beside a blue Due now.

Pausing or archiving the dashboard is how you stop the retries.

### Failure alert emails

You get an email once a dashboard has failed a chosen number of times in a row.
Set the threshold in Settings, then Alerts: the options are **2, 3, or 5**, and
the default is 3.

- One email per outage, not one per failed run, plus a reminder roughly every 7
  days while it stays broken. A monthly dashboard reminds every 30 days.
- One recovery email on the next run that records a real success.
- Alerts can be muted per dashboard from the schedule dialog. A muted dashboard
  never alerts, and unmuting mid-outage does not retroactively fire.
- A free plan never receives the email, but the outage is still tracked, so
  upgrading during one alerts on the next failure rather than swallowing it.

## If your plan lapses

Refresh does not fail and nothing is deleted. Each due run records a **skipped**
run with the reason `tier_lapsed`, the schedule is preserved, you get one notice
email, and re-subscribing resumes it automatically.

A `tier_lapsed` skip does not send a failure alert, and it does not count as the
recovery that closes an outage.

## Check it worked

1. Open [dashies.ai/app/schedules](https://dashies.ai/app/schedules). Your
   dashboard shows the cadence you set and a **next run** time.
2. Wait for that time to pass, plus the half hour described above, then open the
   History tab. A run should be listed.
3. A successful run marked **No change** is a healthy result, not a failure. It
   means the SQL re-ran and produced byte-identical numbers.
4. If nothing appears at all, check the dashboard is actually refreshable: ask
   your AI for its refresh status. A dashboard with no schedule and no next run
   was published without a working refresh manifest, which is usually a data
   source scope problem. See [Work as a team](/guides/work-as-a-team).
