Skip to content

Cron schedule

Cron every minute

To run a cron job every minute, use * * * * *. An asterisk in all five fields matches every minute of every hour of every day, which works out to 1,440 runs a day.

Every minute
Expression* * * * *
Runs1,440 times a day
systemd OnCalendar*:*:00

How it works

One minute is the finest resolution classic cron has. The daemon wakes up once a minute, compares the current time against every line, and starts each job that matches. With five asterisks every comparison succeeds, so the job is started at second 0 of every minute, in practice a moment later, depending on how busy the daemon is.

There is no macro for this schedule: @hourly is the most frequent one. */1 * * * * and 0-59 * * * * mean the same thing as * * * * * and nobody writes them.

Before settling on every minute, check whether the job is really polling for work. 1,440 process starts a day, each re-reading config and opening new connections, often cost more than one long-running worker or a queue consumer that reacts immediately.

Field-by-field breakdown
FieldValueMeaning
Minute*every minute
Hour*every hour
Day of month*every day of the month
Month*every month
Day of week*every day of the week

Next runs

Scheduler clock

As on GitHub Actions without timezone, Vercel, Cloudflare and Kubernetes with timeZone "Etc/UTC".

Next run times, computed in your browser from the current time
RunYour timeUTC
1Calculating… 
2  
3  
4  
5  

Ready-to-paste versions

The same schedule for each scheduler, with what differs on each one.

crontab (Linux, macOS, BSD)

crontab -e
# m h dom mon dow  command
* * * * * /usr/local/bin/job.sh >> /var/log/job.log 2>&1

# Same, but skip a run while the previous one is still going:
* * * * * flock -n /tmp/job.lock /usr/local/bin/job.sh
  • cron uses the server’s time zone. On cronie (Fedora, RHEL), a CRON_TZ=Europe/London line above the entry changes the zone for the entries below it.

GitHub Actions

.github/workflows/scheduled.yml
on:
  schedule:
    - cron: '*/5 * * * *'  # GitHub’s minimum
  workflow_dispatch: {}
  • GitHub Actions can’t run a schedule every minute: the docs set the shortest interval at once every 5 minutes, so */5 * * * * is as close as it gets, and even that can be delayed at busy times.

Kubernetes CronJob

cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: scheduled-job
spec:
  schedule: "* * * * *"
  timeZone: "Etc/UTC"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: job
              image: busybox:1.36
              command: ["/bin/sh", "-c", "date; echo running"]
  • spec.timeZone is stable since Kubernetes 1.27; without it, the kube-controller-manager’s zone applies. concurrencyPolicy: Forbid skips a run while the previous Job is still active.

Vercel Cron Jobs

vercel.json
{
  "crons": [
    { "path": "/api/cron", "schedule": "* * * * *" }
  ]
}
  • Vercel always uses UTC, doesn’t accept names like MON or JAN, and won’t let you set both day of month and day of week.
  • This runs more than once a day, so it needs a Pro or Enterprise plan. Per Vercel’s docs, a Hobby deployment with an expression like this fails.

Cloudflare Workers

wrangler.toml
[triggers]
crons = ["* * * * *"]
  • Cron Triggers run on UTC. Changes can take up to 15 minutes to propagate across Cloudflare’s network.

node-cron (Node.js)

scheduler.js
import cron from 'node-cron';

// 6 fields: the first one (seconds) is optional
cron.schedule('0 * * * * *', async () => {
  await runJob();
}, { timezone: 'UTC', noOverlap: true });
  • The schedule lives inside the Node process: if it’s down, nothing runs, and three replicas run the job three times. noOverlap skips a tick while the previous run is still going.

systemd timer

job.timer + job.service
# /etc/systemd/system/job.timer
[Unit]
Description=Run job.service every minute

[Timer]
OnCalendar=*:*:00

[Install]
WantedBy=timers.target

# /etc/systemd/system/job.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/job.sh

# systemctl daemon-reload && systemctl enable --now job.timer
  • Check it with systemd-analyze calendar '*:*:00', which prints the normalized form and the next elapse. AccuracySec defaults to 1min, so the start can drift by up to a minute.

Spring @Scheduled and Quartz

Java
@Scheduled(cron = "0 * * * * *", zone = "UTC")
public void runJob() {
    // ...
}

// Quartz CronTrigger:
CronScheduleBuilder.cronSchedule("0 * * * * ?")
  • In Spring, the first of the 6 fields is seconds; the rest follow standard cron (0 or 7 = Sunday).
  • In Quartz, one of the two day fields must be ?, so the day-of-week field gets it.

Pitfalls

Overlapping runs

If a run can take longer than 60 seconds, the next one starts while it’s still going; cron doesn’t check. Prefix the command with flock -n /tmp/job.lock so a second copy exits immediately instead of piling up.

Hosted schedulers may not go this low

GitHub Actions’ minimum is 5 minutes, and Vercel’s Hobby plan allows one run per day. A real cron daemon, Kubernetes, Cloudflare Workers, Vercel Pro or an in-process scheduler will fire every minute.

Mail and log noise

cron emails any output of a job to the crontab owner (or MAILTO). At 1,440 runs a day that floods a mailbox. Redirect stdout and stderr to a log file, or to /dev/null if you truly don’t need them.

Frequently asked questions

Is * * * * * the same as */1 * * * *?
Yes. A step of 1 over the whole range selects every value, so both match every minute. * * * * * is the conventional form.
Does a cron job every minute start at exactly second 0?
It is due at second 0, but cron only promises the minute. The daemon checks once a minute and forks jobs one after another, so a start a second or two late is normal.
Can GitHub Actions run a workflow every minute?
No. GitHub’s documentation sets the shortest interval for scheduled workflows at once every 5 minutes, and scheduled runs can be delayed further under load.
How do I run a job every minute only during work hours?
Restrict the hour and weekday fields: * 9-17 * * 1-5 runs every minute from 09:00 to 17:59, Monday to Friday.

Last reviewed by Arielton Oberek.