---
term: 'Scheduled Cloud Code (Cron Jobs)'
seoTitle: 'Cron Jobs & Scheduled Cloud Code: Syntax, DST, Reliability'
headline: 'What is Scheduled Cloud Code (Cron Jobs)?'
slug: scheduled-cloud-code-cron-jobs
category: backend-compute
shortDefinition: 'A cron job is a task that runs automatically on a time schedule; scheduled Cloud Code applies the idea to serverless functions.'
relatedTerms:
  - background-jobs-task-schedulers
  - cloud-code-serverless-functions
  - database-triggers-beforesave-aftersave
  - serverless-architecture
contrastsWith:
  - background-jobs-task-schedulers
aboutTerms:
  - 'Cron Expression'
  - 'Crontab'
  - 'Misfire Policy'
faq:
  - question: 'What is a cron job?'
    answer: 'A task scheduled to run automatically at fixed times or intervals — classically by the cron daemon on Unix systems reading a crontab, and by extension any time-triggered job on any platform. The name comes from chronos, Greek for time.'
  - question: 'What do the five fields in a cron expression mean?'
    answer: 'Minute (0–59), hour (0–23), day of month (1–31), month (1–12), day of week (0–7, where both 0 and 7 are Sunday), followed by the command. Asterisk means every value; commas list, dashes range, slashes step.'
  - question: 'What are @daily, @hourly, and @reboot?'
    answer: 'Shorthand strings replacing the five fields: @hourly, @daily, @weekly, @monthly, @yearly map to their obvious expressions, and @reboot runs once when the daemon starts — a nonstandard but widely supported extension.'
  - question: 'How do I create and manage cron jobs?'
    answer: 'crontab -e edits your table, crontab -l lists it, and crontab -r removes it entirely — famously adjacent to -e on the keyboard and unprompted, so prefer -ri. Each line is a schedule plus a command; the daemon checks every minute.'
  - question: 'What happens if the machine is off at the scheduled time?'
    answer: 'Classic cron simply skips the run — there is no catch-up. That is why anacron exists for intermittently powered machines, why systemd timers offer a persistence option, and why modern schedulers make catch-up policy an explicit setting rather than a surprise.'
  - question: 'How does cron handle daylight saving time?'
    answer: 'Badly, by default: per the manual itself, jobs scheduled in the springtime "missing hour" never run, and times that occur twice at fall-back run twice. The standing advice: schedule in UTC and keep critical jobs out of the local 00:00–03:00 window.'
  - question: 'What if a job is still running when the next run starts?'
    answer: 'Classic cron happily starts a second copy — and a third. Overlap needs an explicit answer: a lock file that makes the late run skip, or the formalized policies of modern schedulers — allow, forbid, or replace the running instance.'
  - question: 'How do I know when a cron job fails?'
    answer: 'By default, you don''t — output goes to local mail nobody reads, and a schedule that never fires produces no error at all, because nothing ran. The pattern that fixes it: heartbeat monitoring — the job pings a URL on success, and the absence of the ping raises the alarm.'
  - question: 'Can cron run a job more often than once a minute?'
    answer: 'No — one minute is classic cron''s floor; the daemon wakes, scans, and fires per minute. Second-level granularity needs a different scheduler: Quartz-style six-field expressions, a loop inside a service, or an event queue rather than a clock.'
  - question: 'Do I need a server to run cron jobs?'
    answer: 'Not anymore. Serverless platforms attach a schedule directly to a function: the platform owns the clock, fires the job, records logs and status, and retries per policy — a schedule as configuration rather than a file on a machine you must keep alive.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'crontab(5) — Linux manual page'
    url: 'https://man7.org/linux/man-pages/man5/crontab.5.html'
  - name: 'cron — Wikipedia (history and implementations)'
    url: 'https://en.wikipedia.org/wiki/Cron'
  - name: 'Quartz Scheduler — CronTrigger and misfire policies'
    url: 'https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-06.html'
  - name: 'Kubernetes — CronJob concepts'
    url: 'https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/'
cta:
  title: 'Schedules without a server'
  text: 'Define a Cloud Job in code, schedule it in the Back4app dashboard — start time, recurrence, no crontab — and read status and logs where the platform keeps them. The clock is our job; the logic is yours.'
  linkText: 'Start building free'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-07-30'
translationKey: scheduled-cloud-code-cron-jobs
---

**A cron job is a task that runs automatically on a time schedule; scheduled Cloud Code applies the idea to serverless functions.** The lineage runs from Version 7 Unix through [Vixie cron](https://en.wikipedia.org/wiki/Cron) (1987) to today's platform schedulers, and the model barely changed: a daemon wakes every minute, reads a table of *schedule + command* lines — the **crontab** — and fires what matches. What changed is everything around the model: where the clock lives, what happens when a run fails, and whether anyone notices.

## Key takeaways

| Question | Answer |
| --- | --- |
| The syntax | Five fields — minute · hour · day-of-month · month · day-of-week |
| The floor | One-minute granularity; seconds need a different scheduler |
| The gotchas | DST skips and double-fires · the day-of-month/day-of-week OR rule |
| The reliability gap | Classic cron: no retries, no catch-up, no cluster, silent failure |
| The modern form | Schedule as platform config on a function — clock, logs, and retries managed |

## Cron in one screen

```text
┌ minute (0–59)   ┌ hour (0–23)   ┌ day of month (1–31)   ┌ month   ┌ day of week (0–7)
*                 *               *                        *         *        command

0 2 * * *        daily at 02:00          */15 * * * *   every 15 minutes
0 9 * * 1-5      weekdays at 09:00       0 6,18 * * *   06:00 and 18:00
0 0 1,15 * *     the 1st and 15th        @daily         = 0 0 * * *
@reboot          once at daemon start    @hourly        = 0 * * * *

crontab -e   edit your table      crontab -l   list it
crontab -ri  remove (with prompt — bare -r wipes it, no questions asked)
```

The modern equivalent — the job in code, the schedule in a dashboard, the client just reading results:

**JavaScript:**

```javascript
// JavaScript — Cloud Code (cloud/main.js)
// A scheduled job: defined in code, scheduled in the dashboard
Parse.Cloud.job('nightlyReport', async (request) => {
  const since = new Date(Date.now() - 24 * 60 * 60 * 1000);

  // Idempotent by date key: a rerun overwrites tonight's report, not duplicates
  const existing = await new Parse.Query('DailyReport')
    .equalTo('runDate', dateKey(new Date()))
    .first({ useMasterKey: true });
  const report = existing ?? new Parse.Object('DailyReport');

  report.set('runDate', dateKey(new Date()));
  report.set('summary', await summarizeOrdersSince(since));
  await report.save(null, { useMasterKey: true });
  request.message('Report written'); // shows in the dashboard's job status
});
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// Clients consume what the schedule produces — no crontab in sight
final query = QueryBuilder<ParseObject>(ParseObject('DailyReport'))
  ..orderByDescending('runDate')
  ..setLimit(1);
final latest = (await query.query()).results?.first as ParseObject?;
print(latest?.get<String>('summary'));
// The report exists because a scheduled Cloud Job ran at 02:00 UTC —
// defined in code, scheduled in the dashboard, logged by the platform.
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// Clients consume what the schedule produces — no crontab in sight
let latest = try await DailyReport.query()
    .order([.descending("runDate")])
    .first()
print(latest.summary ?? "")
// The report exists because a scheduled Cloud Job ran at 02:00 UTC —
// defined in code, scheduled in the dashboard, logged by the platform.
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// Clients consume what the schedule produces — no crontab in sight
val query = ParseQuery.getQuery<ParseObject>("DailyReport")
query.orderByDescending("runDate")
query.limit = 1
val latest = query.find().firstOrNull()
println(latest?.getString("summary"))
// The report exists because a scheduled Cloud Job ran at 02:00 UTC —
// defined in code, scheduled in the dashboard, logged by the platform.
```

## The gotchas the man page knows

Four semantics from [crontab(5)](https://man7.org/linux/man-pages/man5/crontab.5.html) that surprise nearly everyone. **The OR rule:** when *both* day-of-month and day-of-week are restricted, the job fires when *either* matches — `0 0 13 * 5` runs on the 13th *and* every Friday, not only on Friday the 13th. **DST, verbatim:** jobs scheduled in the spring-forward "missing hour" *never run*; times that occur twice at fall-back *run twice* — schedule in UTC, keep critical work out of the local small hours. **Steps reset at field boundaries:** `*/90` in the minute field cannot mean "every 90 minutes" — the counter resets each hour; true odd intervals need a real scheduler. **The minute floor:** the daemon scans once a minute; anything finer is another tool's job.

## The reliability gap

Classic cron is a scheduler, not a reliability system, and the gap has a shape: **no retries** (a failed run is a failed run); **no catch-up** (a machine asleep at 02:00 skips the run — `anacron` and systemd timers' persistence option exist precisely for this); **no cluster story** (two servers with the same crontab run everything twice; one server is a single point of failure); **silent failure** (output mails a local account nobody reads). Modern schedulers answer each gap with named policy: **misfire policies** ([Quartz's](https://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/tutorial-lesson-06.html) fire-now vs. skip), **concurrency policies** ([Kubernetes'](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/) allow/forbid/replace for overlapping runs), and deadline-based skip semantics — while honestly documenting that distributed scheduling is *approximately* once: a run may occasionally double or not fire at all. Which yields the discipline both worlds share: **scheduled jobs must be idempotent** — keyed on their period (the code tabs' report keyed by date) so a rerun overwrites rather than duplicates, and a missed run is recoverable by running late.

```mermaid
flowchart LR
  accTitle: A scheduled serverless function with monitoring
  accDescr: A schedule configured in the platform dashboard fires a cloud job at the set recurrence. The job runs with logs and status recorded by the platform, writes its idempotent results to the database, and pings a heartbeat monitor on success, so a missed or failed run is detected by the absence of the ping.
  D["Dashboard schedule<br/>02:00 UTC daily"] --> C["Platform clock fires"]
  C --> J["Cloud Job runs<br/>status + logs recorded"]
  J -->|"idempotent write<br/>keyed by date"| DB[("Database")]
  J -->|"on success"| HB["Heartbeat ping"]
  HB -.->|"ping absent past grace<br/>period → alert"| M["Monitor"]
```

## Classic cron vs. systemd timers vs. distributed schedulers vs. scheduled functions

| | Classic cron | systemd timers | Distributed (Quartz/K8s-style) | Scheduled cloud functions |
| --- | --- | --- | --- | --- |
| Lives | One machine's crontab | One machine, unit files | A cluster | Platform config on a [function](/glossary/cloud-code-serverless-functions/) |
| Catch-up | None (anacron bolts it on) | `Persistent=true` | Misfire policies | Platform policy |
| Overlap | Starts another copy | Serialized per unit | allow / forbid / replace | Platform policy |
| Retries | None | Service restart rules | Configurable | Built in |
| Failure visibility | Local mail, unread | journald | Job status objects | Dashboard status + logs |
| Server to keep alive | Yes — and it's the SPOF | Yes | The cluster | **No** |

## Watching schedules

Scheduled failure is the quietest failure in computing: a job that never fired emits *nothing* — no exception, no log line, no email — because nothing ran. The pattern that fixes it inverts the alarm: **heartbeat monitoring** — the job pings a URL on successful completion, the monitor expects the ping within a grace period, and *absence* triggers the alert. Pair it with the mundane hygiene classic cron never had: run duration tracked over time (the report that took 4 minutes last month and 40 tonight is telling you something), output captured to real logs instead of local mail, and the schedule inventory documented — because a crontab scattered across five servers is how organizations discover jobs they forgot they ran.

## Common use cases

- **Reports and digests** — the nightly rollup the code tabs sketch: aggregate, write, notify.
- **Cleanup and expiry** — TTL sweeps, orphan pruning, session and token expiration passes.
- **Data synchronization** — periodic pulls from third-party systems that offer no [webhooks](/glossary/webhooks/).
- **Reminders and re-engagement** — time-based sends: trial endings, abandoned carts, renewal notices.
- **Health and reconciliation** — the scheduled audit that catches what event-driven paths missed.

## Which scheduler should you use? A decision matrix

| Situation | Reach for |
| --- | --- |
| One Linux box you already operate | Classic cron — with locks and a heartbeat |
| Laptop-grade or intermittent machines | anacron / systemd timers with persistence |
| A cluster you run anyway | Its native scheduled-job controller |
| App backend on a BaaS | Scheduled Cloud Jobs — no server, logs included |
| Sub-minute or odd intervals | A real scheduler or queue, not crontab arithmetic |
| Event-shaped work mislabeled as scheduled | The [job queue](/glossary/background-jobs-task-schedulers/) — cron only feeds it |

## Limitations and trade-offs

- **Time triggers describe when, not whether.** A schedule fires regardless of whether there's work; event-driven [triggers](/glossary/database-triggers-beforesave-aftersave/) and queues fit work that arrives irregularly.
- **Approximate-once is the honest contract.** Even managed schedulers occasionally double-fire or skip; idempotency is the job's responsibility everywhere.
- **Timezones are a policy decision.** UTC schedules survive DST; local-time schedules serve humans — pick deliberately, document loudly.
- **Frequency has a floor and a price.** Minute-level classic cron, platform-dependent floors elsewhere; polling-by-cron at high frequency is usually a queue wearing a clock.
- **Schedules accumulate silently.** Every "temporary" nightly job is permanent until inventoried; the dashboard listing them all is an underrated feature.

## Scheduled Cloud Code on Back4app

Back4app is an open-source Backend-as-a-Service (BaaS) platform that combines a managed database, auto-generated REST and GraphQL APIs, authentication, file storage, and Cloud Code serverless functions. Scheduling here is the modern column of the comparison table made concrete: define `Parse.Cloud.job` in [Cloud Code](/glossary/cloud-code-serverless-functions/) — the code tabs' nightly report, idempotent by date key, master-key access for the cross-user aggregation — then schedule it in the dashboard's Background Jobs panel: job name, start time, recurrence, no crontab syntax and no server whose crontab it would live in. Runs, status, and errors land in the server logs and jobs panel — the failure-visibility column answered by default — and the disciplines this article closes with remain yours by design: key jobs to their period, keep them idempotent, and let a heartbeat confirm the platform's clock and your logic agreed tonight, like every night.
