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. peepcrontab(5)for the deets./etc/cron.dβ system crontabs that packages manage live here./etc/anacrontabβ that'sanacrontab(5)./var/spool/cron/crontabsβ users' crontabs live here./dev/shm/systemd-cron.*β queues and tokens used forCRON_BATCH_LOADAVG_BELOWandCRON_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.dand scripts in/etc/cron.schedulemust consist only ofascii(7)alphanumerics, underscores (_), and dashes (-) β they have to match the C-locale regular expression"^[[:alnum:]_-]*$". Anything else gets ignored. And0anacronandanacronare 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.pathandcron-update.serviceβ the path unit monitors βFILESβ and calls the service, which runssystemctl daemon-reloadto 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 toCRON_MAIL_SUCCESS=nonemptyforOnSuccess=).nometadataβ don't includesystemctl statusoutput, and don't add the usualjournalctlmetadata to the output (equivalent toCRON_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
- ubuntu stonking: systemd-cron 2.8.2-1 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms