Kubernetes Cron Expression for CronJobs

A Kubernetes cron expression goes in the spec.schedule field of a CronJob and uses the standard five fields. Build the schedule below, then check the time zone and missed-run settings that decide what really happens.

Last updated: October 8, 2026

The short answer

A Kubernetes cron expression goes in the spec.schedule field of a CronJob and uses the standard five fields. Set spec.timeZone if you do not want the controller's local time.

apiVersion: batch/v1
kind: CronJob
metadata:
  name: nightly-report
spec:
  schedule: "30 2 * * *"
  timeZone: "Etc/UTC"
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 300
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: report
              image: registry.example.com/report:1.4

This runs at 02:30 UTC daily. If a run is more than 300 seconds late it is skipped, and a run is skipped while the previous one is still going.

Build a Kubernetes CronJob schedule

Set the fields and the output follows Kubernetes rules, with the next runs in your time zone. Copy the result or open it in the full Generator.

Kubernetes cron expression syntax

The schedule follows standard five-field cron: minute, hour, day of month, month and day of week, with weekdays as 0-6 or names. Step values such as */2 and 0-23/2 are supported. A ? is accepted and means the same as *. There is no seconds field and no L, W or #; see the cron special characters reference for what those do elsewhere.

Kubernetes also accepts macros:

MacroSame as
@yearly or @annually0 0 1 1 *
@monthly0 0 1 * *
@weekly0 0 * * 0
@daily or @midnight0 0 * * *
@hourly0 * * * *

Kubernetes cron expression examples

Load one into the builder above to change it, then paste the result into spec.schedule.

ExpressionWhat it doesUse
*/5 * * * *Runs every 5 minutes. Load
0 * * * *Runs every hour, on the hour. Load
30 2 * * *Runs at 2:30 AM every day. Load
0 9 * * 1-5Runs at 9:00 AM every weekday (Mon-Fri). Load
0 3 * * 1Runs at 3:00 AM every Monday.
Weekly on Monday.
Load
0 0 1 * *Runs at 12:00 AM on day 1 of every month. Load

Time zone: the controller default and spec.timeZone

With no time zone set, the schedule is read in the local time zone of the kube-controller-manager, which on many clusters is UTC but is not guaranteed to be. Set .spec.timeZone to an IANA name such as America/New_York or Etc/UTC to remove the doubt. This field has been stable since Kubernetes v1.27.

Do not put CRON_TZ= or TZ= inside the schedule string. Kubernetes documents that this is not supported, and the API rejects the resource with a validation error. For conversions and daylight saving time see the cron timezone converter.

Missed runs, deadlines and overlapping jobs

  • startingDeadlineSeconds is how late a Job may start. After the deadline that run is skipped and counted as failed. A value under 10 seconds may stop the CronJob from being scheduled, because the controller checks every 10 seconds.
  • The 100 missed schedules rule. If the controller counts more than 100 missed schedules since the last one, it does not start the Job and logs too many missed start times. Setting startingDeadlineSeconds limits the window it counts.
  • concurrencyPolicy is Allow by default. Forbid skips a run while the previous Job is running, and Replace stops the old Job and starts a new one.
  • Approximate scheduling. Kubernetes can in rare cases create two Jobs or none for one scheduled time, so write Jobs that are safe to repeat.

Common mistakes with Kubernetes cron expressions

  • Using AWS or Quartz syntax with a leading seconds field or a year. Check it with the cron expression validator.
  • Assuming the schedule is in your local time. It is not unless timeZone is set.
  • Running a long Job on a short interval with the default Allow, so runs pile up. Use Forbid or a longer interval; see cron every 5 minutes.
  • Editing a CronJob and expecting running Jobs to change. Existing Jobs continue unchanged.

Sources and further reading