Back to blog

Alternatives · Apr 27, 2026

Vercel Cron every minute: the Hobby hourly limit and how to beat it

Vercel Cron is convenient if you live on Vercel Pro and your schedules are simple. The wall most teams hit is sub-hour cadence on Hobby, no per-schedule timezones, and a redeploy on every cron change. Here is the external cron pattern that fixes all three.
crontap.com / blog
Vercel Cron on Hobby is hourly minimum, capped at 5 jobs, and tied to a redeploy on every cadence change. Here is what it actually does, why teams hit the wall, and the external cron pattern that gives you per-minute schedules, per-IANA timezones, and one dashboard across projects.

You set up Vercel Cron to run every 5 minutes, saved vercel.json, and deployed. Then you opened the Crons tab in your project dashboard and saw your schedule listed as "Every hour". Vercel Cron on Hobby runs once an hour, no exceptions. Even Pro lets you go faster but ties every cadence change to a redeploy and bills $20/mo per user. Here is what it actually does, why teams keep hitting the wall, and the external cron pattern most of them end up running instead.

If you just want the short version: keep your Vercel API route, drop the crons entry from vercel.json, and point Crontap at the route. You get every 1 minute on Pro, per-IANA timezones, unlimited jobs, and one dashboard across every project (and every non-Vercel target) you own.

The actual Vercel Cron limits

Before reaching for an external scheduler, it helps to be clear on what Vercel Cron actually allows on each tier. The numbers below are from Vercel's own usage and pricing docs as of 2026-04, sanity-checked against the Cron Jobs overview.

  • Hobby. Up to 5 cron jobs per project. Hourly minimum cadence (the smallest expression Vercel will accept on Hobby is one that fires at most once per hour). UTC only.
  • Pro. Up to 40 cron jobs per project. Minute-level cadence allowed. UTC only. Cron entries live in vercel.json and ship with every deployment, so a cadence change is a redeploy. Pro is billed at $20/mo per user.
  • Enterprise. Up to 100 cron jobs per project, plus invocation guarantees. Same UTC-only constraint, same redeploy-to-change story.

The two limits people remember are the wrong ones. The hourly minimum on Hobby is famous, but the redeploy-to-change-cadence behaviour bites Pro teams just as hard, especially when you want to flip a schedule from "every 5 minutes" to "every 15 minutes" for a quiet weekend without shipping a deploy.

What Vercel Cron cannot do that an external scheduler can

Once you've shipped a few crons through vercel.json, the gaps show up in roughly this order.

Unlimited jobs

Hobby caps at 5 cron jobs per project. The 6th cron makes you pick: drop a job, merge two jobs into one fan-out endpoint, or upgrade to Pro at $20/mo per user. None of those are great answers if the 6th job is "ping our healthcheck endpoint every 5 minutes". An external scheduler does not care how many schedules you point at it. A Crontap free tier is available and Pro is unlimited.

Change cadence without a redeploy

Cadence in Vercel Cron lives in vercel.json. Changing "every 10 minutes" to "every 30 minutes" means editing the file, opening a PR, getting a review, and waiting for a deploy. For a "ship our morning digest at 7am instead of 8am" kind of change, that is a lot of process for one number. With an external scheduler the cadence is a dropdown in the dashboard and a save click.

Per-schedule IANA timezone

Vercel Cron is UTC only as of 2026 docs. If you have customers in Europe/London, America/New_York, and Asia/Kolkata, and each cohort wants their daily report at 7am local, you cannot express that in vercel.json. You either compute the per-tenant offset in your handler (annoying, breaks across DST changes) or you ship 3 schedules at the right UTC offsets and accept that they drift twice a year.

An external scheduler treats timezone as a per-schedule field. Three schedules, three IANA zones, no DST math.

Cross-project + non-Vercel targets in one dashboard

Vercel Cron is per-project. If you have a frontend, an API, and a worker, each in its own Vercel project, you have three crons tabs to look at. If you also need to fire something on Cloud Run, Railway, or your own VM, Vercel Cron does not help at all (it can only target routes inside the project that owns the vercel.json).

External cron consolidates everything: every Vercel project, every non-Vercel target, every webhook, in one place.

Why this is annoying (real use cases that need sub-hour)

The reason "Hobby is hourly" gets repeated so often is that the work most teams want to schedule is sub-hour. A few patterns that show up over and over:

  • Polling a third-party API every 5 to 15 minutes (Stripe webhooks reconciliation, Shopify Admin API checkout polling, GitHub status syncs).
  • Token refresh for OAuth integrations that expire on a vendor schedule (refresh every hour, but with a buffer so you don't catch the boundary).
  • Scheduled email digests at named local times (07:00 Europe/London, 09:00 America/New_York).
  • Health checks that ping your own endpoints every minute and alert on drift.
  • Cache warming and pre-render triggers ahead of expected traffic spikes.

None of those fit "once an hour, UTC, redeploy to change". If you've hit any of them, you've probably already opened the Pro pricing page and done the math.

The external cron pattern

Here is the shape we recommend. It works whether your code is on Vercel Hobby, Pro, or anywhere else, because the schedule lives outside the deployment.

Crontap (cron)  →  HTTPS POST  →  Your /api/jobs/<job> route  →  the actual work

Vercel still owns the runtime. Crontap owns the clock. The contract between them is one HTTPS call per cadence with a bearer token.

Step 1: Define a public API route in your Next.js or Vercel Edge app

If you already have a vercel.json cron pointing at /api/jobs/refresh-tokens, leave the route in place. If you are starting fresh, create one:

export async function POST(request: Request) {
  const auth = request.headers.get("authorization");
  if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
    return new Response("Unauthorized", { status: 401 });
  }

  await runRefreshTokens();
  return Response.json({ ok: true });
}

Three things to note:

  1. The route is POST so a casual GET from a crawler can't trigger it.
  2. We're using an Authorization header, not a query string token, so the secret never lands in access logs.
  3. The handler returns 200 quickly. If the actual work is slow, kick it off as a background task, log the request, and return immediately. Crontap will time out a long-hanging request just like any other HTTP client.

Step 2: Protect it with a bearer token

Generate a long random string locally and store it as an environment variable in Vercel:

# generate a 32-byte secret
openssl rand -base64 32

Add it as CRON_SECRET in your Vercel project's Environment Variables (Production + Preview + Development as needed) and redeploy once so the variable is live.

If you already use a secrets manager (Doppler, 1Password CLI, AWS Secrets Manager), wire it up the same way you do any other secret. The point is that the route refuses anonymous traffic.

Step 3: Point Crontap at the route with a stored Authorization header

Head to Crontap and create a new schedule.

  1. URL. Paste the production URL of your route, e.g. https://your-app.vercel.app/api/jobs/refresh-tokens or your custom domain.
  2. Method. POST.
  3. Headers. Add Authorization: Bearer <your CRON_SECRET>. Crontap stores the value encrypted; you don't see it again after saving.
  4. Cadence. Type plain English ("every 5 minutes") or paste a cron expression. Crontap previews the next 5 fires inline so you can sanity-check before saving.
  5. Timezone. Pick the IANA zone that matches the schedule's intent (Europe/London for the 7am UK digest, America/New_York for the 9am US digest, UTC for anything that is genuinely UTC).
  6. Failure alerts. Add an integration: email / webhook (Slack / Discord / Telegram). Crontap fires on 4xx and 5xx with the response body and timing in the payload, so a Slack alert is immediately useful.

Press Perform test to fire a real request before you trust the cadence. If the route returns 200, you are done. If you see 401, your bearer is mismatched. If you see 5xx, the route itself failed and that is good news because the alerting just proved itself.

Fix this in 60 seconds with Crontap. Free tier available. No credit card. Schedule your first job →

Side by side: vercel.json vs one Crontap entry

For the same job ("refresh OAuth tokens every 30 minutes in Europe/London"), here is the diff.

vercel.json (Pro plan, UTC only, redeploy required for any cadence change):

{
  "crons": [
    {
      "path": "/api/jobs/refresh-tokens",
      "schedule": "*/30 * * * *"
    }
  ]
}

This entry is UTC. To get "every 30 minutes in Europe/London" you cannot, because Vercel Cron has no timezone field. You either accept UTC and live with the DST drift twice a year, or you compute the right window in your handler. To go from every 30 minutes to every 15 minutes, you edit the schedule string, open a PR, deploy.

A Crontap entry for the same job (saved in the dashboard, no deploy):

  • URL: https://your-app.vercel.app/api/jobs/refresh-tokens
  • Method: POST
  • Headers: Authorization: Bearer <CRON_SECRET>
  • Cadence: */30 * * * * or "every 30 minutes"
  • Timezone: Europe/London
  • Failure alert: Slack webhook, fire on 4xx/5xx

To change the cadence, open the schedule in Crontap, edit the dropdown, save. To add a second timezone, duplicate the schedule, change the timezone field, save. No redeploy.

Pricing math

Vercel Pro is $20/mo per user. A 4-person team is $80/mo before any one of them writes a cron. Vercel Cron is included once you are on Pro, but you've already paid for the seat.

Crontap is $0 on the free tier (free tier available, no credit card). Pro is $3.25/mo billed annually for unlimited schedules at every-1-minute cadence. The cost difference scales linearly with seats: if you only need cron and not the rest of Vercel Pro, an external scheduler is roughly two orders of magnitude cheaper for a small team.

If you are already paying for Vercel Pro for the deployment platform, you are already paying for cron and the per-minute cadence. The wedge then is the timezone story, the redeploy story, and the cross-project / non-Vercel dashboard story, not the dollars.

When to keep using Vercel Cron

External cron is a shape, not a religion. There are cases where the built-in is the right answer.

  • Your team is already on Vercel Pro for the deploy platform, and the cron just happens.
  • One UTC schedule is enough.
  • You don't mind a redeploy to change cadence (because cadence changes are rare).
  • The schedule is tightly coupled to deploy lifecycle; you actually want it to ship and roll back with the code.

For everything else, the external pattern reads cleaner.

FAQ

Can Vercel Cron run every minute?

Only on Pro and Enterprise, per Vercel's pricing docs. Hobby caps at hourly. If you need every minute on Hobby, you need an external scheduler pointing at your route. Crontap goes to every 1 minute on Pro at $3.25/mo billed annually.

Will Vercel Cron and Crontap conflict if I run both?

No. They run independently. Many teams keep one or two vercel.json crons for tightly-coupled-to-deploy schedules and add Crontap for everything that needs per-IANA timezone, sub-hour cadence on Hobby, or cross-project visibility.

What about timezone-aware Vercel Cron?

Vercel Cron is UTC only as of 2026. The workarounds are computing offsets in the handler (DST drift twice a year) or shipping multiple UTC schedules at the right offsets (drift twice a year, again). Crontap stores timezone per schedule and handles DST automatically.

Can I keep my Next.js function and skip Vercel Cron entirely?

Yes. Drop the crons block from vercel.json so the platform stops firing the route, and let Crontap fire it instead. Your function still runs on Vercel; only the clock changes.

What if my route takes 30 seconds to finish?

Vercel Functions have a 30-second default timeout on Hobby and 300-second on Pro. If your work is longer, the answer is the same with or without Vercel Cron: split the work into chunks, kick off a background job, return 200 quickly. Crontap will respect a long-running response, but you don't want your scheduler to be your queue.

Does this work with Edge Functions?

Yes. Edge Functions accept HTTPS calls just like Serverless Functions. The Authorization-header pattern is identical.

References

Related on Crontap

From the blog

Read the blog

Guides, patterns and product updates.

Tutorials on scheduling API calls, webhooks and automations, plus deep dives into cron syntax, timezones and reliability.

Alternatives

Vercel Cron every minute: beating the Hobby hourly limit

Vercel Cron caps Hobby at hourly cadence and 5 jobs, and ties every change to a redeploy. Here is the external cron pattern teams use to ship per-minute schedules, per-IANA timezones, and one dashboard across projects without paying $20/mo per user for Pro.

Alternatives

Cloud Run cron without Cloud Scheduler

Cloud Scheduler costs $0.10 per job per month after the first 3 and asks for OIDC plus IAM bindings on every target. Here is the IAM-free pattern Cloud Run teams use to fire their .run.app URLs on a clock with one bearer token and one dashboard across every GCP project.

Alternatives

Heroku Scheduler alternative: any cron expression without the add-on

Heroku Scheduler caps you at three cadences and account-wide UTC, and spins a one-off dyno per run. Here is the external cron pattern that gives you any cron expression, per-schedule timezones, and zero per-execution dyno spin-up cost.

Guides

Running an OpenAI sentiment pipeline on a real scheduler

OpenAI batch work needs a clock, not a user session. Here is the scheduled HTTP-route pattern teams use to drain LLM batches at a sustainable rate inside OpenAI's rate limits, with per-task failure alerts.

Reference

Cron syntax cheat sheet with real-world examples

Cron syntax without the math. Every pattern you're likely to reach for (every 5 minutes, weekdays, business hours, first of the month), with a practical example and a link to a free debugger.