Home › Vercel Cron Jobs
Vercel Cron Jobs
How to schedule cron jobs on Vercel using vercel.json. Vercel cron jobs invoke a Vercel Function (API route) on a schedule - no separate server needed. Covers syntax, plan limits, security and Next.js examples.
How Vercel Cron Jobs Work
Vercel cron jobs trigger a Vercel Function at a scheduled time by making an HTTP GET request to a path in your project.
You define the schedule in vercel.json at the root of your project. When you deploy, Vercel registers the schedule automatically.
Official reference: Vercel Cron Jobs documentation.
- Cron jobs only run on production deployments - not on preview deployments.
- All schedules run in UTC. There is no per-job timezone option.
- Vercel invokes the function with an HTTP GET request to the configured path.
- Each invocation includes a
vercel-cron/1.0user agent and anx-vercel-cron-scheduleheader.
Vercel Cron Job Configuration
Add a crons array to your vercel.json file. Each entry needs a path and a schedule:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"crons": [
{
"path": "/api/cron/daily-digest",
"schedule": "0 9 * * *"
},
{
"path": "/api/cron/cleanup",
"schedule": "0 2 * * 0"
}
]
}
The path must start with / and point to a Vercel Function or API route.
Deploy with vercel --prod to register the schedules. Changes to vercel.json only take effect after a new deployment.
Vercel Cron Syntax
Vercel uses standard 5-field POSIX cron syntax - the same as Linux crontab. All times are UTC.
* * * * * │ │ │ │ │ │ │ │ │ └── Day of week (0-6, Sunday=0, or SUN-SAT) │ │ │ └──── Month (1-12, or JAN-DEC) │ │ └────── Day of month (1-31) │ └──────── Hour (0-23, UTC) └────────── Minute (0-59)
| Expression | Description |
|---|---|
* * * * * | Every minute (Pro plan only) |
*/15 * * * * | Every 15 minutes |
0 * * * * | Every hour |
0 9 * * * | Every day at 9:00 AM UTC |
0 9 * * 1-5 | Weekdays at 9:00 AM UTC |
0 0 * * 0 | Every Sunday at midnight UTC |
0 0 1 * * | First day of every month |
Vercel Cron Jobs Plan Limits
Plan limits are the most important thing to know before setting up Vercel cron jobs.
| Plan | Max cron jobs | Minimum interval | Notes |
|---|---|---|---|
| Hobby (free) | 2 | Once per day | Cannot run more frequently than daily. Significant limitation for most use cases. |
| Pro | Unlimited | Every minute | Full cron frequency. Invocations count toward function execution quota. |
| Enterprise | Unlimited | Every minute | Dedicated capacity, custom limits. |
Hobby plan: once per day maximum
On the free Hobby plan, cron jobs can run at most once per day. Expressions like */15 * * * * (every 15 minutes) will be rejected at deploy time.
If you need sub-daily frequency, you need the Pro plan or an alternative like a GitHub Actions schedule (free, but with delays) or an external cron service.
Next.js API Route for a Cron Job
Create the function that Vercel will invoke. For Next.js App Router:
// app/api/cron/daily-digest/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
// Verify the request came from Vercel cron
const authHeader = request.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return new NextResponse('Unauthorized', { status: 401 });
}
// Your task logic here
await sendDailyDigest();
return NextResponse.json({ success: true });
}
For Next.js Pages Router:
// pages/api/cron/daily-digest.ts
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(req: NextApiRequest, res: NextApiResponse) {
const authHeader = req.headers['authorization'];
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Your task logic here
res.status(200).json({ success: true });
}
Securing Vercel Cron Jobs with CRON_SECRET
Without security, anyone who knows your API route URL can trigger your cron job manually.
Vercel automatically adds an Authorization: Bearer {CRON_SECRET} header to every cron invocation.
Set up the secret in your project:
1. Go to Vercel Dashboard › Project › Settings › Environment Variables
2. Add a variable named CRON_SECRET with a random string of at least 16 characters
3. Verify it in your function as shown in the examples above
Use a password generator to create a secure value. Vercel also sets CRON_SECRET automatically when you add cron jobs via the dashboard - check your environment variables if you are unsure whether it is set.
Testing Vercel Cron Jobs Locally
Trigger manually via CLI
vercel crons trigger /api/cron/daily-digest
Triggers a deployed cron job immediately without waiting for the schedule. Requires the Vercel CLI and a production deployment.
Curl the endpoint directly
curl -H "Authorization: Bearer your-cron-secret" \ https://your-project.vercel.app/api/cron/daily-digest
Call the API route directly, passing the CRON_SECRET. Works locally with vercel dev too.
Vercel CLI Cron Commands
| Command | What it does |
|---|---|
vercel crons list | List all configured cron jobs for the project |
vercel crons trigger /api/cron/path | Trigger a deployed cron job immediately |
vercel crons add --path /api/cron --schedule "0 2 * * *" | Add a cron job to vercel.json interactively |
Build your Vercel cron expression
Vercel uses standard 5-field Linux cron syntax in UTC. Generate it here and paste it into the schedule field in your vercel.json.