epochkit

Cron expression for every 4 hours

The cron expression 0 */4 * * * runs on the hour, every 4 hours. The restricted fields are minute 0 and hour */4; the remaining asterisks match anything. That works out to 6 runs per day.

0 */4 * * *

Field breakdown

Field-by-field meaning of the cron expression 0 */4 * * *
Field Value Meaning
Minute 0 The top of the hour (:00)
Hour */4 Every 4 hours, counted from 0: 0, 4, 8, 12, 16, 20
Day of month * Every day of the month (1–31)
Month * Every month (1–12)
Day of week * Every day of the week (0–6)

Next runs

Next 5 runs Timezone: UTC

Run times are calculated in your browser timezone. The scheduler that executes the job uses its own — always UTC on Vercel Cron, UTC by default on GitHub Actions, the host clock on crontab.

How this schedule works

Cron evaluates the five fields of 0 */4 * * * — minute, hour, day of month, month, day of week — against the clock once a minute and starts the job on any minute where all five match, which cronstrue reads as "On the hour, every 4 hours": 6 runs per day. The runs land at 00:00, 04:00, 08:00, 12:00, 16:00, 20:00. Twenty-four divides by 4 without a remainder, so the spacing survives midnight: the gap from the 20:00 run to the next day's 00:00 run is the same 4 hours as every other gap.

When to use every 4 hours

Six runs a day suit batch processing that is comfortably slower than the data arrives, long-lived cache refreshes, and housekeeping such as session cleanup or credential rotation. Four hours is roughly the point where a job stops being a poll and starts being a batch: each run can take tens of minutes without crowding the next one out. Choose it when the work is chunky, the upstream is slow-moving, and a four-hour-old view of the world is still a useful one for whoever ends up reading it.

Common mistakes with every 4 hours

Confusing 0 */4 * * * with 0 4 * * * is the usual slip: the first is six runs a day, the second is one run at 04:00. Both parse, neither errors, and the difference only shows up in a dashboard nobody is watching. Beyond that, the mistake specific to four-hourly batches is scope creep inside the job. A run that started at two minutes grows quarter by quarter until it takes an hour — still comfortably inside the interval, so nothing complains, but the output is now an hour staler than everyone assumes. Track the runtime trend, not just the exit code.

Platform snippets

The same expression, ready to paste into the four schedulers that read five-field cron. The notes below each snippet are the ones that follow from this schedule; the cron expression generator lists every caveat for every platform.

GitHub Actions

yaml
name: Scheduled workflow
on:
  schedule:
    - cron: '0 */4 * * *'
  workflow_dispatch:

jobs:
  scheduled:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run job
        run: echo "Running scheduled job"
  • • Workflows scheduled at the top of the hour may be delayed during high-load periods. Consider offsetting the minute field (e.g. "5 */4 * * *") for more reliable timing.

Kubernetes CronJob

yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: my-cron-job
spec:
  schedule: "0 */4 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: job
              image: my-image:latest
              command: ["/bin/sh", "-c", "echo Running"]
          restartPolicy: OnFailure

Vercel Cron

json

Hobby plan limitation: cron jobs can only run once per day. Schedules more frequent than daily will fail to deploy on Hobby. Use Pro plan or above for higher frequency.

{
  "$schema": "https://openapi.vercel.sh/vercel.json",
  "crons": [
    {
      "path": "/api/cron",
      "schedule": "0 */4 * * *"
    }
  ]
}
  • • Pro plan and above: invocations occur within the specified minute (e.g. "5 8 * * *" runs between 08:05:00 and 08:05:59).

crontab

bash
# Edit your crontab: crontab -e
0 */4 * * * /path/to/command

# With logging:
0 */4 * * * /path/to/command >> /var/log/cron.log 2>&1

Variations

Frequently asked questions

How do I read the cron expression 0 */4 * * *?

Read the five space-separated fields left to right as minute, hour, day of month, month, and day of week. In 0 */4 * * * the minute is 0, hour is */4, day of month is *, month is *, day of week is *. Of the operators cron defines, this expression uses only the ones that matter here: an asterisk matches every value in its field and a slash introduces a step counted from the start of the field. Put together, cronstrue reads the whole thing as "On the hour, every 4 hours", and a scheduler that checks all five fields once a minute will start the job 6 runs per day.

What timezone does 0 */4 * * * run in?

The schedule repeats through the day at fixed hours — 00:00, 04:00, 08:00, 12:00, 16:00, 20:00 — and which part of the day those hours fall in depends entirely on the scheduler. Moving between zones does not change how often the job runs; it changes when. GitHub Actions defaults to UTC and takes an optional timezone key next to cron, so the hours can be anchored to an IANA zone. Vercel Cron always evaluates in UTC, with no setting to change it. Kubernetes CronJobs use the controller's local zone unless spec.timeZone is set, and a CRON_TZ prefix inside the schedule string is rejected outright. A crontab follows the host clock unless CRON_TZ overrides it. In any zone that observes daylight saving, the whole set of run hours shifts by one twice a year.

What hours does 0 */4 * * * actually run?

The job runs at 00:00, 04:00, 08:00, 12:00, 16:00, and 20:00 — six times a day, counted from hour 0 rather than from the moment the schedule was installed. Because 4 divides 24 evenly, the four-hour gap holds across midnight. If you need the runs to land on a different set of hours, list them explicitly: 2,6,10,14,18,22 in the hour field keeps the same cadence shifted two hours later. Remember that the hours are read in the scheduler's timezone, so on Vercel Cron 00:00 always means midnight UTC, and on GitHub Actions it means midnight UTC unless the workflow sets the optional timezone key.

Related cron schedules

Build a custom schedule in the cron expression generator, or browse every epochkit tool.