---
title: Scheduled jobs
description: Code that runs on a schedule, from an app's jobs/ folder.
section: Server
order: 4
---

# Scheduled jobs

<p class="lead">A job is a function that runs on a schedule (nightly at 2am, every Monday…) with the same server API as the rest of your code. No cron, queue or worker to set up.</p>

```js title="jobs/tidy-drafts.js"
export const schedule = "0 6 * * 1-5";   // weekdays at 06:00 UTC

export default async function (ctx) {
  const stale = await ctx.collection("drafts").list({ filter: "updated < @days_ago.30" });
  // clean up, send a digest, …
}
```

- One file per job in `jobs/`, beside `functions/`.
- Nothing in `jobs/` is exposed over HTTP; jobs only run on schedule.
- A job runs as the system, with the same `ctx` as a [server function](/docs/server-functions) and `CRON` as its method.
- `export const atStart = true` also runs it once when the server starts, e.g. to reset demo data right after a deploy.

## The schedule

Five fields of standard cron, in UTC: minute, hour, day of month, month, day of week (`0` is Sunday).

| | |
|---|---|
| `0 2 * * *` | Daily at 02:00 |
| `*/15 * * * *` | Every 15 minutes |
| `0 8 * * 1` | Mondays at 08:00 |
| `0 9 1 * *` | 09:00 on the 1st of each month |
| `@hourly`, `@daily`, `@weekly`, `@monthly` | Shorthands |

`*`, `*/n`, `a-b`, `a-b/n` and lists are supported. The schedule is parsed from the file's source, so listing jobs never executes app code.

## How they run

- Every minute, matching jobs run.
- A job never overlaps itself: if the previous run is still going, the next one is skipped.
- Like cron, runs missed while the server was down are not caught up.

**Jobs** in the admin UI lists every job with its last run and result, and can run one on demand. Backups are listed there too: off until you set a schedule and how many to keep.
