The config
{
"crons": [
{
"path": "/api/cron/daily",
"schedule": "0 9 * * *"
}
]
}The path must be a route that exists in your deployment. Vercel issues a GET request to it on schedule.
All five fields are required
Vercel rejects shorthand. @daily and other @ aliases fail validation, and so does any expression with fewer than five fields. Non-standard characters like L, W and # are not supported either.
UTC only, and plan limits are tight
Schedules always run in UTC — there is no timezone setting. Check what your expression means locally using the selector above.
Hobby plans are limited to a small number of cron jobs that can only run once per day, and the exact trigger minute is not guaranteed. Pro and Enterprise allow more jobs and finer intervals. Vercel changes these limits periodically — confirm against their current pricing page before designing around them.
Secure the endpoint
Your cron path is a public HTTP route: anyone who guesses it can trigger your job. Set a CRON_SECRET environment variable and reject requests whose Authorization header doesn't match.
export function GET(request) {
const auth = request.headers.get('authorization');
if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response('Unauthorized', { status: 401 });
}
// ... your job
}
Frequently asked questions
What timezone do Vercel cron jobs use?
UTC. There is no timezone configuration option.
Does Vercel cron support @daily?
No. Vercel requires the full 5-field expression — use 0 0 * * * instead of @daily.
How do I secure a Vercel cron endpoint?
Set a CRON_SECRET environment variable and verify the Authorization: Bearer header inside the route handler.
Related cron expressions
Browse the full cron expression reference, or build your own expression from scratch.