How to add cron jobs on Vercel
Configure Vercel cron jobs in vercel.json with a crons array specifying path and schedule cron expression, create a matching API route endpoint, deploy to production, and monitor in the dashboard. Free tier limits to 1-2 jobs with daily frequency; use Pro for more. Design handlers as idempotent and secure with CRON_SECRET.
Prerequisites
- Vercel account and project linked to Git
- Serverless or Edge Function API route knowledge
- Basic cron expression syntax
- Familiarity with Vercel deployments
- Node.js or TypeScript for handlers
Step-by-Step Instructions
Create Serverless or Edge Function endpoint
api/cron.ts or app/api/cron/route.ts in Next.js. This handles cron invocations via HTTP GET. Example for Node.js: import type { VercelRequest, VercelResponse } from '@vercel/node';
export default function handler(req: VercelRequest, res: VercelResponse) {
// Your task logic here (make idempotent for duplicates)
res.status(200).json({ success: true });
} Path must start with /; test locally with curl http://localhost:3000/api/cron.Secure the cron endpoint
CRON_SECRET (random 16+ chars) in Vercel dashboard. Check Authorization header in handler: const authHeader = req.headers.authorization;
if (!process.env.CRON_SECRET || authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return res.status(401).json({ success: false });
}
// Proceed with task Vercel auto-sends it as Bearer token on invocation.Configure vercel.json at project root
vercel.json with crons array. Each job needs path (starts with /, e.g. "/api/cron") and schedule (5-field cron string, UTC). Example for daily 5 AM: {
"crons": [
{
"path": "/api/cron",
"schedule": "0 5 * * *"
}
]
} Examples: every 24h "0 0 * * *", hourly "0 * * * *".Deploy to production
main) for auto-deploy, or use CLI vercel --prod. Crons activate only on production deployments (previews ignored). Invocations hit your prod URL like https://your-project.vercel.app/api/cron. Post-build, jobs are live.Verify in Vercel Dashboard
requestPath:/api/cron.Monitor and test locally
curl http://localhost:3000/api/cron (prod skips redirects). Dashboard shows invocations, errors. Jobs non-concurrent by default; duration matches Function limits.Update or disable crons
vercel.json (change schedule/path or remove), redeploy. Or use dashboard Disable Cron Jobs button (re-enable via redeploy). Changes reflect post-deploy.Handle concurrency and idempotency
Common Issues & Troubleshooting
Cron not triggering or no dashboard entry
Ensure production deployment (previews ignored); redeploy via Git push to main or vercel --prod. Check Cron Jobs tab.
Build fails with invalid config
Validate vercel.json JSON and cron syntax (5 fields, path starts with /). Hobby: once/day max.
401 Unauthorized on invocation
Set CRON_SECRET env var and verify Authorization: Bearer ${process.env.CRON_SECRET} in handler.
Timeouts or cold starts
Optimize handler; add ?__no_cache=1 query if cached. Upgrade to Pro for better reliability.
Frequent jobs fail on Hobby
Free/Hobby limits 1-2 jobs, daily only. Upgrade to Pro for up to 40 jobs, any frequency.