Opyntel

Vercel cron jobs: why one did not run, and how to know next time

Vercel cron jobs run by sending a GET request to a path on your production deployment, on a schedule set in vercel.json. When one does not run, check that the schedule is in UTC, that the path is deployed to production, that it does not redirect, and that your own CRON_SECRET check is not rejecting Vercel. Vercel does not retry a failed run and sends no alert, so the logs under the project’s Cron Jobs settings are the only record unless something else watches them.

How Vercel runs a cron job

vercel.json
{
  "crons": [{ "path": "/api/cron/sync", "schedule": "0 5 * * *" }]
}

Vercel calls https://<your-production-domain>/api/cron/sync with the user agent vercel-cron/1.0 and an x-vercel-cron-schedule header. Preview deployments never run crons. Changing a schedule takes a new production deployment.

Why a Vercel cron job did not run

CauseWhat to check
The schedule is in UTCVercel cron expressions are always UTC, not your timezone
Hobby plan timingOn Hobby a cron runs at most once a day and may fire at any minute within the hour you set
Not on productionOnly the production deployment runs crons; check the path exists there
The path redirectsCron requests do not follow redirects, so a trailing-slash or locale redirect ends the run
Your auth check rejects itVercel sends Authorization: Bearer $CRON_SECRET only when the CRON_SECRET variable is set for production
Crons are disabledDisable Cron Jobs in the project settings stays on across deployments
It timed outA cron has the same duration limit as any Vercel Function
Delivery is best effortA rare run is never delivered and leaves no log line at all

Check the logs

Open the project’s Settings → Cron Jobs and pick View Logs next to a job. It opens the runtime logs filtered to the job’s path, with the status of each invocation. Responses that redirect or come from the cache are not logged. From a terminal:

bash
vercel crons ls                  # the project's cron jobs
vercel crons run /api/cron/sync  # trigger the deployed cron now
curl -H "Authorization: Bearer $CRON_SECRET" https://<your-production-domain>/api/cron/sync

Make the job safe to miss or repeat

Vercel may skip a run or deliver one twice, and a long job can overlap the next one. Write the job to process everything since its last successful run, make each step safe to repeat, and take a lock (for example in Redis) so two runs cannot work at once. The general causes, outside Vercel, are in why a cron job is not running.

How Opyntel watches Vercel cron jobs

With a Vercel log drain, available on Vercel Pro and Enterprise, Opyntel sees every cron invocation with its status and duration. It alerts when a run fails and when an expected run does not arrive, by email, Slack or SMS depending on your plan. Your cron jobs sit in one dashboard next to the rest of your Vercel projects and the other platforms you run.

FAQ

Vercel cron jobs questions, answered

Retries, timezones, testing and preview deployments.

No. A failed run is not retried; the next run happens at the next scheduled time.

Always UTC. Convert your local time before writing the schedule.

Run vercel crons run with its path, trigger it from the deployment summary, or call its path on the production domain with the Authorization header if you check CRON_SECRET.

No. Only the production deployment runs cron jobs.

The alerts your platform doesn’t send.

One dashboard for everything you run, with the alerts your platforms leave out. Read-only, nothing to install in your apps.

See how it works