Vercel Cron Jobs Guide
Vercel Cron Jobs let a Next.js (or any Vercel) project trigger a serverless function on a schedule, configured declaratively in vercel.json using standard cron syntax — no separate infrastructure or queue needed, but with plan-based limits on frequency and count that are easy to hit without realizing it.
Syntax Notes
Standard 5-field cron syntax in the vercel.json 'crons' array, each entry pairing a 'path' (the API route to invoke) with a 'schedule' string — Vercel always evaluates and runs schedules in UTC, regardless of your project or account's regional settings.
Examples
{
"crons": [
{
"path": "/api/cleanup",
"schedule": "0 0 * * *"
}
]
}if (req.headers.get('authorization') !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response('Unauthorized', { status: 401 })
}{
"crons": [
{ "path": "/api/hourly-sync", "schedule": "0 * * * *" },
{ "path": "/api/daily-report", "schedule": "0 8 * * *" }
]
}Gotchas
- Vercel's Hobby (free) plan limits cron jobs to once per day per cron and caps the total number of crons per project — a job configured for */15 * * * * on a Hobby plan is silently limited to a single daily run rather than erroring outright, a frequent source of confusion.
- Any endpoint used as a cron target is a public URL unless you explicitly verify the request — Vercel recommends checking a bearer token (via a CRON_SECRET environment variable) in the handler, since without it, anyone who discovers the endpoint URL can trigger it manually.
- Cron schedules are always evaluated in UTC — there's no per-project timezone setting, so an expression meant for '9 AM local time' needs to be manually offset to the equivalent UTC hour, and that offset shifts with daylight saving time.
Best Practices
- Check your plan's cron limits (frequency and total count) in Vercel's dashboard before deploying a schedule more frequent than daily — Hobby-tier restrictions apply silently rather than with a build-time error.
- Always verify the CRON_SECRET bearer token inside the handler function, since Vercel Cron invokes a normal public API route with no built-in access control of its own.
- Convert the desired local time to UTC manually when writing the schedule string, and re-check it twice a year around daylight saving transitions if the job is time-sensitive.
Frequently Asked Questions
- Can I run a Vercel cron job more than once a day on the free plan?
- No — the Hobby (free) plan restricts cron jobs to a maximum of once per day, regardless of what schedule string you configure; more frequent schedules require a Pro or Enterprise plan.
- Are Vercel cron endpoints secure by default?
- No — a cron-configured API route is a normal public endpoint. Vercel recommends checking a bearer token against a CRON_SECRET environment variable inside the handler to prevent anyone else from triggering it.
- What timezone do Vercel cron schedules run in?
- Always UTC — there's no per-project timezone configuration, so convert your intended local time to its UTC equivalent when writing the schedule, and account for daylight saving time shifts.
Related Tools
Platform Guides
Cron syntax for Linux, Kubernetes, AWS, and more
Supabase Cron (pg_cron) Guide
Schedule recurring database jobs in Supabase with the pg_cron extension: cron.schedule() syntax, calling Edge Functions, and common gotchas.
Linux Cron Guide
How to schedule jobs with cron on Linux: crontab -e, standard 5-field syntax, log locations, and common gotchas. Complete guide with examples.