> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiveku.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Schedule Recurring Tasks with Cron Jobs

> Run serverless functions on a timer

Need to send a daily email, run a weekly cleanup, or sync data every few minutes? Hiveku's Cron Jobs run your serverless functions on a schedule.

## Enable Cron Jobs

<Steps>
  <Step title="Open Hosting">
    In your project, click **Hosting** in the sidebar, then open the **Cron Jobs** tab.
  </Step>

  <Step title="Toggle cron jobs on">
    Flip the **Cron Jobs** switch to enabled. This activates the scheduler for your project.
  </Step>
</Steps>

## Add a Cron Job

<Steps>
  <Step title="Click Add Cron Job">
    The form asks for four fields.
  </Step>

  <Step title="Function path">
    The route or function to trigger. Examples:

    ```
    /api/cron/daily-report
    /api/jobs/cleanup
    /api/sync/stripe
    ```

    Your function should respond to a GET or POST — the scheduler calls it.
  </Step>

  <Step title="Schedule">
    Pick a preset (Every minute, Every hour, Daily at midnight) or enter a custom cron expression. See [Schedule Expressions](#schedule-expressions) below.
  </Step>

  <Step title="Environment">
    Pick **Production only** (most common) or **Staging & Development** for testing.
  </Step>

  <Step title="Description (optional)">
    A note so future-you knows what this job does. *"Daily revenue report to finance Slack"* is better than nothing.
  </Step>

  <Step title="Save">
    The job appears in your list and is now scheduled.
  </Step>
</Steps>

## Schedule Expressions

All times are **UTC**. Do the math for your timezone.

### Cron Syntax

```
cron(minute hour day month day-of-week year)
```

| Expression                | Runs                               |
| ------------------------- | ---------------------------------- |
| `cron(0 9 * * ? *)`       | 9:00 AM daily                      |
| `cron(0 */2 * * ? *)`     | Every 2 hours                      |
| `cron(0 9 ? * MON-FRI *)` | 9 AM weekdays                      |
| `cron(*/15 * * * ? *)`    | Every 15 minutes                   |
| `cron(0 0 1 * ? *)`       | Midnight on the 1st of every month |

### Rate Syntax

For simple intervals, use `rate()`:

```
rate(5 minutes)
rate(1 hour)
rate(1 day)
```

<Info>
  Use `?` in either the day-of-month or day-of-week field, not both. `cron(0 9 * * ? *)` is valid; `cron(0 9 * * * *)` is not.
</Info>

## Alternative: `@schedule` Comment

Instead of creating a job in the UI, you can mark a function with an `@schedule` comment and Hiveku auto-detects it.

```typescript theme={null}
// app/api/cron/daily-report/route.ts

// @schedule cron(0 9 * * ? *)
export async function GET() {
  // runs at 9 AM UTC daily
  await sendDailyReport();
  return Response.json({ ok: true });
}
```

The next deploy picks up the comment and registers the schedule. Edit the comment, redeploy, and the schedule updates.

<Tip>
  `@schedule` keeps schedules in git alongside the code. Great for team workflows where you want schedule changes reviewed in PRs.
</Tip>

## Testing a Job

### Run Now Button

Every job has a **Run Now** button in the Cron Jobs list. Click it to trigger the function immediately, as if the schedule just fired.

### Execution History

Below each job you'll see recent runs with:

* Timestamp
* Duration
* HTTP status
* Any errors returned

Click a run to see the logs from that execution.

## Pausing and Deleting

<Tabs>
  <Tab title="Pause">
    Click the **Pause** toggle on a job to stop it from running without deleting it. Useful during maintenance.
  </Tab>

  <Tab title="Resume">
    Toggle **Pause** off to re-enable the schedule.
  </Tab>

  <Tab title="Delete">
    Click the trash icon. <Warning>Deletion is permanent. The execution history is wiped with it.</Warning>
  </Tab>
</Tabs>

## Limits to Know

* **Timeout**: each cron execution runs as a serverless function with a **15-minute max runtime**. For longer jobs, break the work into chunks or offload to a queue.
* **Concurrency**: if a run is still going when the next scheduled fire hits, the new fire is skipped (not queued up).
* **Precision**: scheduler accuracy is within a few seconds — don't rely on cron for sub-second timing.

## Verifying a New Cron Job

<Steps>
  <Step title="Click Run Now">
    Test the job triggers manually before waiting for the schedule.
  </Step>

  <Step title="Check execution history">
    A new entry should appear within seconds with status 200 (or your function's success code).
  </Step>

  <Step title="Check your function's output">
    Whatever side effect the job does (email sent, row inserted, log written) should have happened. Confirm in the relevant system.
  </Step>

  <Step title="Wait for the first scheduled run">
    Come back after the schedule time. The history should show an automatic run right around that timestamp.
  </Step>
</Steps>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Job didn't run at the scheduled time">
    Three common causes:

    1. **Cron Jobs toggle is off** — confirm it's enabled at the top of the page
    2. **Timezone math is wrong** — schedules are UTC; `cron(0 9 ...)` is 9 AM UTC, which might be 2 AM or 5 PM your time
    3. **Environment mismatch** — a job set to Production-only won't run in Staging
  </Accordion>

  <Accordion title="Job shows errors in history">
    Click the failed run and check the logs. Common issues: missing env var, timeout on a slow API call, unhandled exception. Open **Hosting > Logs** for the full function log around that timestamp.
  </Accordion>

  <Accordion title="Function times out at 15 minutes">
    That's the hard limit on serverless runtime. Split the work: have the cron fire a short function that enqueues tasks to a queue (SQS, or a DB table your app polls), then process them in smaller chunks.
  </Accordion>

  <Accordion title="My @schedule comment isn't registering">
    Make sure:

    1. The comment is on the same line or immediately above the exported handler
    2. The syntax is exactly `// @schedule cron(...)` or `// @schedule rate(...)`
    3. You've redeployed since adding the comment
  </Accordion>

  <Accordion title="Two runs overlap and break each other">
    If your function can take longer than the schedule interval, guard it with a lock. Use a DB row, Redis, or even a simple file check — bail early if the previous run is still in progress.
  </Accordion>
</AccordionGroup>

## What's Next?

<CardGroup cols={2}>
  <Card title="Environment Variables" icon="key" href="/how-tos/env-vars">
    Config secrets your jobs need
  </Card>

  <Card title="Deploy your site" icon="rocket" href="/how-tos/deploy-site">
    Ship your cron functions
  </Card>
</CardGroup>
