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.0 user agent and an x-vercel-cron-schedule header.

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)
ExpressionDescription
* * * * *Every minute (Pro plan only)
*/15 * * * *Every 15 minutes
0 * * * *Every hour
0 9 * * *Every day at 9:00 AM UTC
0 9 * * 1-5Weekdays at 9:00 AM UTC
0 0 * * 0Every 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.

PlanMax cron jobsMinimum intervalNotes
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

CommandWhat it does
vercel crons listList all configured cron jobs for the project
vercel crons trigger /api/cron/pathTrigger 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.