Cron Jobs
Schedule background tasks on Vercel with DirectoryLaunch — secure cron endpoints with CRON_SECRET, read the cron config and add your own jobs.
Cron jobs are scheduled HTTP requests that Vercel fires on a timetable. DirectoryLaunch ships with two.
What's scheduled
"crons": [
{ "path": "/api/cron/competitions", "schedule": "15 8 * * *" },
{ "path": "/api/cron/winner-reminders", "schedule": "0 9 * * *" }
]| Endpoint | When | What it does |
|---|---|---|
/api/cron/competitions | 08:15 UTC daily | Closes competitions that have ended, picks winners, triggers notifications |
/api/cron/winner-reminders | 09:00 UTC daily | Emails winners who haven't yet claimed their prize |
Both paths are regular Next.js API routes under app/api/cron/. You can run them manually with curl — useful for testing.
How cron URLs are protected
Anyone on the internet could hit https://your-site.com/api/cron/competitions otherwise. To prevent that, every cron endpoint checks this header:
Authorization: Bearer ${CRON_SECRET}
Vercel automatically adds the header when it calls your cron endpoints, using the CRON_SECRET env var. If CRON_SECRET is missing or wrong → the endpoint returns 401 Unauthorized.
Generating a good CRON_SECRET
openssl rand -hex 32Paste that into both .env.local and Vercel → Settings → Environment Variables.
Vercel plan limits
| Plan | Cron rate limit |
|---|---|
| Hobby (free) | 1 cron, runs up to once per day |
| Pro | Multiple crons, any schedule |
| Enterprise | No limits |
If you're on Hobby, the default config will hit the limit. Either:
- Keep one cron and disable the other
- Upgrade to Pro
Reading cron schedules
The format is standard Unix cron: min hour day month weekday. Examples:
| Expression | When |
|---|---|
0 * * * * | Every hour on the hour |
*/15 * * * * | Every 15 minutes |
0 9 * * * | 09:00 UTC daily |
0 9 * * 1 | 09:00 UTC every Monday |
0 0 1 * * | Midnight UTC on the 1st of each month |
Use crontab.guru to sanity-check.
Vercel cron schedules are UTC. Convert from your local time before scheduling.
Adding a new cron job
Fastest path — hand the whole job to AI:
Or do it by hand:
1. Create the endpoint
import { NextRequest } from 'next/server';
export async function GET(req: NextRequest) {
// Verify the request is from Vercel cron
const auth = req.headers.get('authorization');
if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// Do your work
// ...
return Response.json({ ok: true });
}2. Register the schedule
Edit vercel.json:
"crons": [
{ "path": "/api/cron/my-task", "schedule": "0 */6 * * *" }
]3. Deploy
Vercel reads vercel.json on deploy and wires the schedule. Changes to schedules require a redeploy.
Testing locally
Manually hit your endpoint with the secret:
curl -H "Authorization: Bearer $CRON_SECRET" \
http://localhost:3000/api/cron/competitionsIt should return { "ok": true } (or whatever your handler returns).
Monitoring
Vercel Settings → Cron Jobs shows each cron's last run status and logs. Failures appear in your project's Logs tab with a cron- prefix.