getNodi

Cron jobs on Vercel, and what Hobby will not run

Vercel runs cron jobs from vercel.json, and on Hobby it runs them once a day. This is what the limits actually are, and what to do if your schedule does not fit inside them.

What Vercel gives you

Vercel Cron Jobs. A crons array in vercel.json. Vercel makes an HTTP GET to a path in your production deployment on that schedule, with a vercel-cron/1.0 user agent.

Minimum interval (Hobby)
Once per day
Minimum interval (Pro)
Once per minute
Precision (Hobby)
Within the hour — ±59 minutes
Cron jobs per project
100 on every plan
Timezone
UTC only

Checked against Vercel docs on 18 August 2026. These change — if a deploy disagrees with this page, believe the deploy and tell us.

When this is the right answer

Most people reading this should keep what they have. It is worth being specific about when:

  • The job genuinely only needs to run once a day, and you are on Hobby.
  • You are on Pro and a minute of granularity in UTC is enough.
  • The work finishes inside your function timeout and nobody minds when exactly it ran.

Where it runs out

Hobby rejects sub-daily schedules at deploy time

This is not a job that runs late — the deployment itself fails, with "Hobby accounts are limited to daily cron jobs". An every-15-minutes schedule that worked locally stops your release.

Hobby fires anywhere within the hour

A job written for 01:00 can run at 01:59. If something downstream assumes it already ran, that hour is a real window of wrongness.

The syntax is narrower than standard cron

Names like MON and JAN are not supported, and day-of-month and day-of-week cannot both be set. Both are accepted by crontab.guru and by most cron libraries, so the expression looks fine right up until the build fails.

No timezone, and no history

Everything is UTC, so a 09:00 job drifts an hour against your working day twice a year. And when a run fails you get whatever your function logged, not a record of the run.

Scheduling it from outside

Keep the route you already have. A Vercel cron job is just a GET to a path, so anything that can make that request on a schedule can drive it — including us. Delete the crons entry, point a getNodi job at the same URL, and pick the schedule you actually wanted.

The route stays exactly as it is — only the caller changes

// app/api/cron/route.ts — unchanged
export async function GET(request: Request) {
  const auth = request.headers.get('authorization');
  if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
    return new Response('Unauthorized', { status: 401 });
  }
  await doTheWork();
  return Response.json({ ok: true });
}

Set the same Authorization header on the getNodi job and it is stored encrypted. Your plan on Vercel does not change, and neither does the route.

What getNodi adds

getNodi calls a URL on a schedule and tells you what happened. Any schedule down to your plan’s floor, in your timezone rather than UTC, with retries, a record of every run — status, latency, response — and an alert the first time one fails. Credentials are encrypted at rest and requests can be HMAC-signed so your endpoint can verify they came from us.

The free plan runs 3 jobs hourly and needs no card, which is enough to find out whether this works for you. What it will not do is run a container, hold a connection open for an hour, or execute your code — it makes HTTP requests, and everything above is a way of making that enough.

Everything stated above about Vercel comes from its own documentation, linked at the top. We have tried to describe it as its makers would. ← What getNodi is