C.W.K.
Stream
Lesson 07 of 10 · published

Cron and launchd

~12 min · cron, launchd, schedule

Level 0Window Tourist
0 XP0/95 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Two ways to schedule things

On Linux servers, cron is the historical scheduler. On macOS, Apple deprecated cron in favor of launchd — a service manager that doubles as a scheduler. Both are still around, but launchd is the recommended path on a Mac.

cron quick reference

crontab -e                 # edit your cron table
crontab -l                 # list it
*/5 * * * * /path/to/script.sh
0   3 * * 1 /path/to/weekly.sh

Five fields: minute hour day-of-month month day-of-week. cron runs as a stripped-down shell with a tiny PATH. Always set absolute paths and source what you need explicitly: 0 3 * * * . $HOME/.zshenv && /path/to/script.sh.

launchd LaunchAgent

Place a plist in ~/Library/LaunchAgents/. Load with launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.me.mytask.plist. Schedule via StartInterval (seconds) or StartCalendarInterval (cron-like dictionary). Survives reboot, supports auto-restart on crash.

<plist>
<dict>
  <key>Label</key>          <string>com.me.daily</string>
  <key>ProgramArguments</key> <array><string>/path/to/daily.sh</string></array>
  <key>StartCalendarInterval</key>
    <dict><key>Hour</key><integer>3</integer><key>Minute</key><integer>0</integer></dict>
  <key>StandardOutPath</key> <string>/tmp/daily.log</string>
</dict>
</plist>

Pippa note: APScheduler in-process

Pippa's heartbeat schedules don't use cron or launchd. They run inside pippa serve via APScheduler. launchd's only role is keeping pippa serve alive. The schedules themselves are in-process for ergonomics. So crontab -l on the office Mac is empty — that is by design.

When to use which

  • Linux server → cron (or systemd timers).
  • macOS → launchd LaunchAgent (user) or LaunchDaemon (root).
  • App-internal schedules → embed a scheduler (APScheduler, node-cron) and let the OS keep your process alive. Often the cleanest path.

Code

Bootstrap a launchd agent·bash
# Place plist
vim ~/Library/LaunchAgents/com.me.daily.plist
# Load (idempotent enough; bootout first if it was loaded)
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.me.daily.plist
# Inspect
launchctl list | grep com.me.daily
# Run now without waiting for schedule
launchctl kickstart gui/$UID/com.me.daily

External links

Exercise

Pick a tiny script (echo hello at $(date) >> /tmp/heartbeat.log). Schedule it: cron with */5 * * * *, or write a launchd plist with StartInterval 300. Verify by tailing /tmp/heartbeat.log.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.