Cron expression for Every day at 4am
0 4 * * *
Runs once a day at 4am, every day.
Next 5 runs (your local time)
These are shown in your browser’s timezone. The job itself runs in the scheduler’s timezone — often UTC — so the real run time can differ.
What people actually schedule with 0 4 * * *
- Post-backup verification and offsite replication — running after the 2–3am dump finishes so it operates on a complete file
- Rebuilding derived datasets (recommendations, aggregates) that depend on the night's ETL having already landed
- Sending overnight digest emails timed to land in inboxes just before the workday starts
Use 0 4 * * * on your platform
It’s the same 5-field expression everywhere — what changes is where you put it and which timezone it runs in.
Linux / crontab
0 4 * * * /path/to/your-command
Runs in the server’s local timezone — check it with timedatectl.
Full field reference: crontab(5) man page.
GitHub Actions
on:
schedule:
- cron: "0 4 * * *"
GitHub Actions always runs scheduled jobs in UTC — there is no timezone setting, and runs can be delayed under load (official docs).
Kubernetes CronJob
spec:
schedule: "0 4 * * *"
Defaults to UTC. Set spec.timeZone (Kubernetes 1.27+)
for a specific zone — see the
CronJob docs.
Quartz / Spring @Scheduled
Quartz uses 6 fields (seconds first): 0 0 4 * * *. Watch out:
Quartz day-of-week is 1=SUN … 7=SAT (not 0–6), and day-of-month /
day-of-week use ? — double-check if your schedule touches those fields
(Quartz cron reference).
Gotchas with every day at 4am schedules
- 4am assumes the 2–3am jobs already finished — verify, don't assume. If your backup at 2am occasionally runs 2.5 hours, a
0 4 * * *replication job starts copying a half-written dump. Gate on a sentinel: have the backup write/var/run/backup.doneand have this jobtest -fit (and check its mtime is today) before proceeding. - Digest emails fired at 4am hit the wrong time zone. 4am server-time is pre-dawn locally but could be mid-morning or mid-afternoon for users elsewhere, landing your "good morning" email at the bottom of an already-full inbox. Compute send time per-recipient time zone in the job, or schedule per-region instances.
- It's the start of the cloud-provider maintenance window. Many managed databases and load balancers default their maintenance window to roughly 3–5am, so a 4am job can hit a forced failover or a brief connection reset mid-run. Make the job idempotent and retry-safe, and check your provider's configured maintenance window so you're not scheduling straight into it.
Will you know if this job silently fails?
Cron jobs fail quietly — a server reboots, a path changes, or an error code is ignored — and nobody notices until the data is missing. A cron monitor (a dead-man’s-switch) alerts you when a scheduled job does not check in on time.
Monitor your cron jobs with UptimeRobot →
Disclosure: this is an affiliate link — we may earn a commission if you sign up, at no extra cost to you.
Is 0 4 * * * the right schedule?
If this job depends on a backup, don't pick a fixed hour and hope — but if you must, 3am is too early to assume completion. For digest emails that must land at the reader's local breakfast, 9am per-time-zone beats a blind 4am UTC blast.
Or use the interactive cron generator & explainer, read the complete cron syntax guide, or pick another common schedule: