systemd-based (Ubuntu, Fedora, Arch, etc.)
journalctl -u cron # or crond on some distros journalctl -u cron --since "1 hour ago"
syslog-based (older systems)
grep CRON /var/log/syslog
To capture stdout/stderr to a file, redirect output in the crontab entry directly, or add logging inside your `scheduled()` handler. **Manually uninstalling without code:**
Edit your crontab and remove the "# bun-cron: <title>" comment
and the command line below it
crontab -e
Or remove ALL bun cron jobs at once by filtering them out:
crontab -l | grep -v "# bun-cron:" | grep -v "--cron-title=" | crontab -
### macOS
Bun uses [launchd](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html) to register jobs. Each job is installed as a plist file at:
~/Library/LaunchAgents/bun.cron.<title>.plist
The plist uses `StartCalendarInterval` to define the schedule. Complex patterns with ranges, lists, or steps are supported — Bun expands them into multiple `StartCalendarInterval` dicts via Cartesian product. **Viewing registered jobs:**
launchctl list | grep bun.cron
**Logs:** stdout and stderr are written to:
/tmp/bun.cron.<title>.stdout.log /tmp/bun.cron.<title>.stderr.log
For example, a job titled `weekly-report`:
cat /tmp/bun.cron.weekly-report.stdout.log tail -f /tmp/bun.cron.weekly-report.stderr.log
**Manually uninstalling without code:**
Unload the job from launchd
launchctl bootout gui/$(id -u)/bun.cron.<title>
Delete the plist file
rm ~/Library/LaunchAgents/bun.cron.<title>.plist
Example for a job titled "weekly-report":
launchctl bootout gui/$(id -u)/bun.cron.weekly-report rm ~/Library/LaunchAgents/bun.cron.weekly-report.plist
### Windows
Bun uses [Windows Task Scheduler](https://learn.microsoft.com/en-us/windows/win32/taskschd/task-scheduler-start-page) with XML-based task definitions. Each job is registered as a scheduled task named `bun-cron-<title>` using [`CalendarTrigger`](https://learn.microsoft.com/en-us/windows/win32/taskschd/taskschedulerschema-calendartrigger-triggergroup-element) elements and [`Repetition`](https://learn.microsoft.com/en-us/windows/win32/taskschd/taskschedulerschema-repetition-triggerbasetype-element) patterns. Most cron expressions are fully supported, including `@daily`, `@weekly`, `@monthly`, `@yearly`, ranges (`1-5`), lists (`1,15`), named days/months, and day-of-month patterns.
#### User context
Tasks are registered using [`S4U` (Service-for-User)](https://learn.microsoft.com/en-us/windows/win32/taskschd/taskschedulerschema-logontype-simpletype) logon type, which runs jobs as the registering user even when not logged in — matching Linux `crontab` behavior. No password is stored. TCP/IP networking (`fetch()`, HTTP, WebSocket, database connections) works normally. The only restriction is that S4U tasks cannot access [Windows-authenticated network resources](https://learn.microsoft.com/en-us/windows/win32/taskschd/security-contexts-for-running-tasks) (SMB file shares, mapped drives, Kerberos/NTLM services). On headless servers and CI environments where the current user’s [Security Identifier (SID)](https://learn.microsoft.com/en-us/windows/security/identity-protection/access-control/security-identifiers) cannot be resolved — such as service accounts created by [NSSM](https://nssm.cc/) or similar tools — `Bun.cron()` will fail with an error explaining the issue. To work around this, either run Bun as a regular user account, or create the scheduled task manually with `schtasks /create /xml <file> /tn <name> /ru SYSTEM /f`.
#### Trigger limit
**Expressions that work on all platforms:**
Pattern
Trigger strategy
Count
`*/5 * * * *`
Single trigger with [`Repetition`](https://learn.microsoft.com/en-us/windows/win32/taskschd/taskschedulerschema-repetition-triggerbasetype-element) (PT5M)
1
`*/15 * * * *`
Single trigger with Repetition (PT15M)
1
`0 9 * * MON-FRI`
One `CalendarTrigger` per weekday
5
`0,30 9-17 * * *`
2 minutes × 9 hours
18
`@daily`, `@weekly`, `@monthly`, `@yearly`
Single trigger
1
**Expressions that fail on Windows** (but work on Linux and macOS):
Pattern
Why
Trigger count
`*/7 * * * *`
9 minute values × 24 hours
216
`*/8 * * * *`
8 minute values × 24 hours
192
`*/9 * * * *`
7 minute values × 24 hours
168
`*/11 * * * *`
6 minute values × 24 hours
144
`*/13 * * * *`
5 minute values × 24 hours
120
`*/15 * * 6 *`
Month restriction prevents Repetition: 4 × 24
96
`0,30 * 15 * FRI`
OR-split doubles triggers: 2 × 24 × 2
96
The key factor is whether the expression can use a [`Repetition`](https://learn.microsoft.com/en-us/windows/win32/taskschd/taskschedulerschema-repetition-triggerbasetype-element) interval (single trigger) or must expand to individual `CalendarTrigger` elements. Minute steps that **evenly divide 60** (`*/1`, `*/2`, `*/3`, `*/4`, `*/5`, `*/6`, `*/10`, `*/12`, `*/15`, `*/20`, `*/30`) use Repetition and work regardless of other fields. Steps that don’t divide 60 (`*/7`, `*/8`, `*/9`, `*/11`, `*/13`, etc.) must be expanded, and with 24 hours active, the count quickly exceeds 48. To work around it, simplify the expression or restrict the hour range:
// ❌ Fails on Windows: /7 with all hours = 216 triggers await Bun.cron("./job.ts", "/7 * * * *", "my-job");
// ✅ Works: restrict to specific hours (9 values × 5 hours = 45 triggers) await Bun.cron("./job.ts", "*/7 9-13 * * *", "my-job");
// ✅ Works: use a divisor of 60 instead (Repetition, 1 trigger) await Bun.cron("./job.ts", "*/5 * * * *", "my-job");
#### Windows containers
**Viewing registered jobs:**
schtasks /query /tn "bun-cron-<title>"
List all bun cron tasks
schtasks /query | findstr "bun-cron-"
**Manually uninstalling without code:**
schtasks /delete /tn "bun-cron-<title>" /f
Example:
schtasks /delete /tn "bun-cron-weekly-report" /f
Or open **Task Scheduler** (taskschd.msc), find the task named `bun-cron-<title>`, right-click, and delete it.
* * *
## `Bun.cron.remove()`
Remove a previously registered cron job by its title. Works on all platforms.
await Bun.cron.remove("weekly-report");
This reverses what `Bun.cron()` did:
Platform
What `remove()` does
Linux
Edits crontab to remove the entry and its marker comment
macOS
Runs `launchctl bootout` and deletes the plist file
Windows
Runs `schtasks /delete` to remove the scheduled task
Removing a job that doesn’t exist resolves without error.