Tidy Dev Tools

Cron every day at midnight

Expression: 0 0 * * * — At 00:00, every day.

At 00:00, every day

Next 5 runs in UTC, from 1 Jan 2026 (example)

When to use it

Midnight is the default slot for daily backups, cleanup scripts, invoice generation and report e-mails. Both the minute and the hour are fixed at zero, while day, month and weekday stay open, so the job runs once per calendar day. Because so many systems pick exactly this moment, shared databases, storage buckets and third-party APIs are often busiest right at 00:00 — moving a heavy job a little later usually makes it faster and more reliable. Daily jobs also give natural checkpoints: name output files after the date, keep a rolling retention window, and verify restorability of backups regularly.

Field by field

FieldValueMeaning
Minute0only 0
Hour0only 00:00
Day of the month*every day of the month
Month*every month
Day of the week*every day of the week

Real-world example

30 2 * * * pg_dump -Fc shop | gzip > /backups/shop-$(date +\%F).sql.gz

Daily database backup at 02:30. Note the escaped percent sign: in a crontab, an unescaped % starts the command input and silently breaks the line.

Variants

ExpressionMeaning
@dailyAt 00:00, every day — same schedule, shorter to write
30 2 * * *At 02:30, every day — daily at 02:30, a quieter time for backups
0 0 * * 1-5At 00:00, on weekdays (Monday to Friday) — midnight on weekdays only

Pitfalls

  • Midnight in which zone? Servers and cloud schedulers usually run in UTC, which is not midnight for your users.
  • A job at 00:00 that processes "yesterday" must compute the date carefully across month and year boundaries.
  • In a crontab, % must be written as \% — date +%F works in a shell but not in a cron line.

Questions

How do I run something at the end of each month instead?

Cron has no last-day keyword. Schedule 55 23 28-31 * * and let the script continue only when tomorrow is the first, e.g. [ "$(date -d tomorrow +\%d)" = 01 ] with GNU date.

Does 0 0 * * * use my local midnight?

It uses the time zone of the machine or scheduler running cron. Check with date on the server, or set CRON_TZ in cronie and timeZone in Kubernetes.

Should backups run at midnight?

Prefer a quieter, randomised minute such as 02:37. Fewer jobs compete for disks and networks, and a failure still leaves time to retry before the working day.

The same schedule elsewhere

  • GitHub Actions: on: schedule: - cron: '0 0 * * *'. Always UTC, and runs can start several minutes late when runners are busy.
  • Kubernetes CronJob: schedule: "0 0 * * *"; set concurrencyPolicy: Forbid to prevent overlapping pods and timeZone if you need local time.
  • Cloudflare Workers: crons = ["0 0 * * *"] under [triggers] in wrangler.toml, evaluated in UTC.

Before you deploy

Use absolute paths, because cron starts commands with a minimal PATH and without your shell profile. Make the job idempotent so a late or repeated run does no harm, log its exit code, and let a dead-man's-switch monitor alert you when an expected run never happens.

Other schedules