Vercel’s Cron Jobs let you run serverless functions on a schedule, but they don’t actually run when you think they do.
Let’s see a cron job in action. Imagine you have a simple serverless function in api/cron/daily-report.js that sends an email.
// api/cron/daily-report.js
export default function handler(request, response) {
console.log('Daily report cron job triggered!');
// ... logic to generate and send report ...
response.status(200).send('Daily report sent.');
}
You configure this to run daily using a cron syntax in your vercel.json:
// vercel.json
{
"crons": [
{
"path": "/api/cron/daily-report",
"schedule": "0 0 * * *"
}
]
}
This schedule: "0 0 * * *" means "at minute 0 of hour 0, every day." You’d expect this to run precisely at midnight UTC. However, Vercel’s Cron Jobs operate on a slightly different model. They don’t guarantee millisecond precision or even minute-level accuracy for every single invocation across their global infrastructure. Instead, they guarantee that your function will be invoked at least once within a given minute.
The actual execution might be a few seconds or even up to a minute later than the exact minute specified. This is a crucial distinction: Vercel prioritizes global availability and resilience over strict, single-server-like timing.
Here’s the mental model:
- The Problem: You need to perform recurring tasks (e.g., sending reports, cleaning up data, syncing information) at predictable intervals without maintaining your own servers.
- The Solution: Vercel Cron Jobs. You define a serverless function and a schedule (using standard cron syntax). Vercel handles the execution.
- How it Works Internally: Vercel has a distributed system that monitors scheduled tasks. When a scheduled minute arrives, Vercel’s infrastructure triggers the corresponding serverless function. It’s not a single cron daemon; it’s a fleet of schedulers. The system aims for "at least once per minute" for a given schedule, meaning if
0 0 * * *is set, the function will run sometime between00:00:00and00:00:59UTC. The exact second can vary due to network latency, load balancing, and the distributed nature of the execution environment. - The Levers You Control:
path: This is the URL path to your serverless function. It must be a valid path within your Vercel project.schedule: This uses standard cron syntax (minute, hour, day of month, month, day of week). Vercel supports the*wildcard.- Serverless Function Logic: The code inside your function determines what actually happens when it’s triggered.
When you set schedule: "0 */4 * * *" (every 4 hours), Vercel aims to run your function at 00:00, 04:00, 08:00, 12:00, 16:00, and 20:00 UTC. The actual execution time within those minutes can drift.
The scheduling mechanism is designed to be robust. If one Vercel edge function execution environment is temporarily unavailable, another will pick up the slack. This means you might see a function trigger at 04:01:15 UTC one day and 04:00:30 UTC the next. For tasks that require precise timing, like financial transactions that must occur at an exact second, Vercel Cron Jobs might not be the right fit. But for most background tasks, this level of "at least once per minute" is perfectly adequate and provides much higher availability than a single server.
Most developers miss that the schedule is a target minute, not a precise execution timestamp. Vercel guarantees invocation within that minute, not at the start of that minute. If you inspect your Vercel Function Logs, you’ll see the actual X-Vercel-Cron-Triggered-At header, which shows the precise UTC timestamp of invocation, and it will always be within the target minute.
The next concept you’ll likely explore is handling retries and idempotency within your scheduled functions.