SYSTEMD.CRON(7)

πŸŽ€ systemd.cron β€” the manual page, but make it cute

okay so bestie, you know how cron is that old reliable guy who just... runs your scripts on a schedule? ✨ Well this page is about the systemd version of that whole vibe β€” the units that do the cron thing without actually being cron. Let's get into it πŸ’…


✨ SYNOPSIS ✨

cron.target
cron-update.path, cron-update.service
cron-mail@.service

🌸 DESCRIPTION 🌸

These units give you the functionality that the classic cron daemon usually provides β€” running the scripts sitting in /etc/cron.schedule directories, and sending mail when something fails. no cap 🫢

Crontabs get watched by cron-update.path, and they're automatically translated by systemd-crontab-generator(8). it's giving ✨*automation*✨


πŸ’– FILES πŸ’–

  • /etc/crontab β€” the administrator's system crontab. peep crontab(5) for the deets.
  • /etc/cron.d β€” system crontabs that packages manage live here.
  • /etc/anacrontab β€” that's anacrontab(5).
  • /var/spool/cron/crontabs β€” users' crontabs live here.
  • /dev/shm/systemd-cron.* β€” queues and tokens used for CRON_BATCH_LOADAVG_BELOW and CRON_BATCH_THROTTLE_GROUP.

and then the schedule directories, one per vibe:

  • /etc/cron.hourly β€” directory for scripts to be executed every hour.
  • /etc/cron.daily β€” directory for scripts to be executed every day.
  • /etc/cron.weekly β€” directory for scripts to be executed every week.
  • /etc/cron.monthly β€” directory for scripts to be executed every month.
  • /etc/cron.yearly β€” directory for scripts to be executed every year.

and the timer overrides πŸ‘‘

  • /usr/lib/systemd/system/schedule.timer
  • /etc/systemd/system/schedule.timer

Native systemd timers will override cron jobs with the same name. ✨

You can also use this mechanism to mask an unneeded crontab provided by a package via systemctl mask package.timer. masking is literally just "no thank u" but in systemd 😌

ok important one bestie 🚨 File names of crontabs in /etc/cron.d and scripts in /etc/cron.schedule must consist only of ascii(7) alphanumerics, underscores (_), and dashes (-) β€” they have to match the C-locale regular expression "^[[:alnum:]_-]*$". Anything else gets ignored. And 0anacron and anacron are always ignored, no exceptions πŸ’€

πŸ‘‘ UNITS πŸ‘‘

  • cron.target β€” the target unit that starts all the others. You need to enable it to actually use systemd-cron.
  • cron-update.path and cron-update.service β€” the path unit monitors β€œFILES” and calls the service, which runs systemctl daemon-reload to re-run the generator. πŸ”
  • cron-mail@.service β€” sends mail in case a cron service unit fails, succeeds, or succeeds-but-only-if-it-wrote-something.

ok so about that instance name: the bit after the @ is the unit name, followed by optional arguments delimited by colons (:). The arguments are:

  • nonempty β€” exit silently if the unit produced no output (equivalent to CRON_MAIL_SUCCESS=nonempty for OnSuccess=).
  • nometadata β€” don't include systemctl status output, and don't add the usual journalctl metadata to the output (equivalent to CRON_MAIL_FORMAT=nometadata).
  • verbose β€” log the reason before exiting silently.
upper-case arguments are ignored, bestie. don't yell at it, it won't listen πŸ™ˆ

Overriding this via systemctl edit can be useful β€” especially for units under /etc/cron.*: set $SENDMAIL or $MAILFROM to override the defaults (which are sendmail(1) and "root", respectively). 🌈

$SENDMAIL can also be set from the global systemd environment (systemctl show-environment). periodt.


πŸ’€ BUGS πŸ’€

Do not use with a cron daemon or anacron, otherwise scripts may be executed multiple times. like, double-running your scripts is not the slay you think it is 😭

All services are run with Type=oneshot, which means you can't use systemd-cron to launch long lived forking daemons. nope, not happening 🚫

Units for non-persistent jobs from crontab(5)s are generated with sequential names. So if a job changes β€” whether by direct editing or by removing (commenting out) a previous job β€” while it is running, and mail is sent for that job, some configuration may be wrong (too new) and systemctl status may be confusing. The journal output and e-mail subject are correct though, so don't panic. 🫢 Setting CRON_UNIQUE_UNITS will work around this (but break existing systemctl edit overrides). tradeoffs, bestie πŸ’…


⭐ EXTENSIONS ⭐

Jobs with PERSISTENT=true and @-keyword are started on boot if a run was missed while the system was off. A regular cron and anacron setup won't catch up on the missed executions of crontabs on reboot. so this is basically the "sorry i missed your call, calling back" feature πŸ“žβœ¨

Generated units log to the journal with CRON_JOB= set to the job line (systemd.journal-fields(7)).


🌸 EXAMPLES 🌸

Start cron units

# systemctl start cron.target

Start cron units on boot

# systemctl enable cron.target

View script output

# journalctl -u cron-daily

Override some generated timer start time

# systemctl edit cron-geoip-database-contrib-root-1.timer

and add

[Timer]
OnCalendar=
OnCalendar=*-*-* 18:36:00

Override cron-daily.service priority, useful for old computers

# systemctl edit cron-daily.service

and add

[Service]
CPUSchedulingPolicy=idle
IOSchedulingClass=idle

Example service file executed every hour

[Unit]
Description=Update the man db

[Service]
Nice=19
IOSchedulingClass=2
IOSchedulingPriority=7
ExecStart=/usr/bin/mandb --quiet

[Install]
WantedBy=cron-hourly.target

πŸ¦‹ NOTES πŸ¦‹

The exact times scripts are executed is determined by the values of the special calendar events hourly, daily, weekly, monthly, and yearly defined in systemd.time(7). so like, the timing is not vibes-based, it's spec-based πŸŽ€


πŸ”₯ DIAGNOSTICS πŸ”₯

systemctl list-timers shows an overview of current timers and when they'll elapse. it's giving schedule glow-up ✨


πŸ‘‘ SEE ALSO πŸ‘‘

crontab(1), systemd(1), crontab(5), systemd.service(5), systemd.timer(5), systemd.unit(5), systemd.time(7), run-parts(8), systemd-crontab-generator(8)


and that's the whole page bestie πŸ’– this is from systemd-cron 2.8.2-1, dated 2026-05-26 β€” go forth and schedule responsibly, mwah 🫢✨🌸

πŸ“¦ where this page comes from