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
{
"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
| Cause | What to check |
|---|---|
| The schedule is in UTC | Vercel cron expressions are always UTC, not your timezone |
| Hobby plan timing | On Hobby a cron runs at most once a day and may fire at any minute within the hour you set |
| Not on production | Only the production deployment runs crons; check the path exists there |
| The path redirects | Cron requests do not follow redirects, so a trailing-slash or locale redirect ends the run |
| Your auth check rejects it | Vercel sends Authorization: Bearer $CRON_SECRET only when the CRON_SECRET variable is set for production |
| Crons are disabled | Disable Cron Jobs in the project settings stays on across deployments |
| It timed out | A cron has the same duration limit as any Vercel Function |
| Delivery is best effort | A 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:
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/syncMake 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.