Dev.to AI ๐Ÿค– Ai ๐Ÿ‘ 0 ๐Ÿ“– 6 min read

Vercel Schedules vs Cron Jobs: when to migrate

If you only need a steady ping to a public route on a fixed cadence, Cron Jobs can stay while Schedules is in beta - but Schedules is where the roadmap lives: per-schedule IANA time zones, private function targets, runti

If you only need a steady ping to a public route on a fixed cadence, Cron Jobs can stay while Schedules is in beta - but Schedules is where the roadmap lives: per-schedule IANA time zones, private function targets, runtime schedules aimed at Queue topics, and toggles without redeploying. Paid usage is metered ($5 per 1M runs and $10 per 1M creations on Pro/Enterprise as of 6 November 2026, per Vercel's changelog). Migration is mostly a vercel.json reshape; the foot-gun is POST-by-default path schedules versus legacy GET Cron hits, and never keep crons and schedules for the same work or you fire twice.

Sources I used: changelog (5 Nov 2026), blog (4 Nov 2026), limits, migration, all read 6 November 2026 - a snapshot, not your invoice.

What Vercel launched (4โ€“5 November 2026)

Vercel introduced Schedules on 4 November 2026 and called public beta on 5 November 2026. Schedules is the successor to Cron Jobs; existing crons keep running and a migration guide exists - no forced cutover.

Cron Jobs were mostly "path + cron in UTC". Schedules keeps static config in vercel.json (or Build Output API), adds runtime create/cancel via @vercel/schedules (SDK/CLI/API), and defaults new Preview static schedules to inactive so a branch doesn't wake production chores by accident.

Comparison table: Schedules vs Cron Jobs

Vercel Schedules (public beta, Nov 2026) Legacy Cron Jobs
Status Public beta; successor product, active development Still supported; existing configs keep running
Static config schedules object in vercel.json / Build Output API crons array in vercel.json
Time zone IANA time zone per schedule UTC only
HTTP method (path targets) Path schedules default to POST Cron Jobs used GET
Private targets Function targets with experimentalTriggers type schedule/v1beta - no public URL, scheduler invokes only Path-based hits are public; protect with CRON_SECRET etc.
Dynamic schedules Runtime create/change/cancel (one-off and recurring) via SDK/CLI/API; dynamic schedules target Queue topics Not a first-class runtime API in the same way
Enable/disable Toggle and run on demand without redeploying Changes typically tied to config/deploy patterns you already know
Preview / custom env New static schedules start inactive on Preview to avoid surprise prod work Same class of "watch what fires where" concerns, less built-in guard
Jitter window Hobby: 15 minutes; Pro/Enterprise: default 1 minute, configurable 1โ€“15 Cron Jobs on Hobby: at most once per day, hour precision; Schedules on Hobby at most every 15 minutes (per Vercel's docs snapshot)
Retries Functions and paths: no automatic retries. Queue topics: retries apply Side effects still hinge on your handler design
Delivery guarantees Duplicates possible - handlers must be idempotent; use execution ID Treat as at least once

Sources: limits, migration, changelog, 6 November 2026.

Static vs dynamic schedules (and targets)

Static schedules (in git): named vercel.json entries on a cron string. Targets: private Function, HTTP path, or Queue topic. Private functions use experimentalTriggers with type schedule/v1beta - no public URL; only the scheduler invokes them. Path targets are normal HTTP and stay public unless you add real auth.

Gotcha: path schedules default to POST; Cron Jobs used GET. The migration guide tells you to set requestMethod to GET when porting handlers that still expect GET.

Dynamic schedules (runtime via SDK/CLI/API) create one-time or recurring work against Queue topics - useful when an AI flow should enqueue a follow-up instead of polling a table. Pair that with durable AI agents: schedules handle when; queues and idempotency handle exactly-once in the real world.

A compact static sketch with a private function, IANA time zone, and the experimentalTriggers hook (shape from Vercel's docs; adapt names to your project):

{
  "functions": {
    "api/reports/scheduled.ts": {
      "experimentalTriggers": [{ "type": "schedule/v1beta" }]
    }
  },
  "schedules": {
    "nightly-report": {
      "schedule": "0 7 * * *",
      "timezone": "Europe/Madrid",
      "function": "api/reports/scheduled"
    }
  }
}

The handler side uses @vercel/schedules (short illustrative example):

import { handleSchedule } from "@vercel/schedules";

export const POST = handleSchedule(async (metadata) => {
  // idempotent work using metadata.executionId in your datastore
  console.log(`${metadata.name} run ${metadata.executionId}`);
});

Dynamic scheduling targets a Queue topic and can carry a payload - useful for agent follow-ups ("remind me to re-check this lead in 36 hours") without cron-sprawl in your database:

import { Schedules } from "@vercel/schedules";

await Schedules.create({
  name: "follow-up-lead-4821",
  // topic must match your Queue consumer wiring
  target: { topic: "agent-followups" },
  expression: { type: "cron", cron: "0 9 * * 1-5" },
  timezone: "Europe/Madrid",
  payload: { leadId: "4821", step: "second-touch" },
});

If you already run site work through one disciplined agent profile, AI webmaster agent is the playbook-shaped version of that idea - runtime schedules plus a queue are the infrastructure-shaped version.

Pricing and limits (6 November 2026)

From the Schedules changelog and limits (6 November 2026):

  • Pro / Enterprise: usage billed from $5 per 1M runs and $10 per 1M creations (metered beyond what your plan includes - check the pricing page for included credits, I am not inventing them).
  • Hobby included monthly: 500 schedule creations and 5,000 runs; over that, Hobby blocks creates/runs until the next billing period (upgrade to Pro to lift the cap).
  • Schedules per team: 1,000 (Hobby), 10,000 (Pro), 100,000 (Enterprise). On Hobby, a deployment can declare up to 100 static schedules.
  • Payload: 16 KB. Execution history: 90 days.

Cron Jobs still bill as Function invocations. Hobby Cron Jobs: โ‰ค100 crons/project, โ‰คonce/day with hour precision; Pro/Enterprise Cron Jobs can go โ‰คonce/minute (per Vercel's Cron docs - verify if you are frequency-bound).

Jitter: Schedules on Hobby use a 15-minute window; Pro/Enterprise default 1 minute, tunable 1โ€“15 minutes. Check your plan in the dashboard before you assume the 1-minute default.

Worked example (marginal math only): if a Pro workspace had 2,000,000 billable schedule runs in a month after included allowance, extra runs at $5/1M are ~$10 on that slice - your dashboard is authoritative; I am illustrating the published rate, not forecasting your bill.

Migrate checklist (GET gotcha, do not keep both)

Per migrate from Cron Jobs: swap crons for named schedules in one deploy, add "requestMethod": "GET" if handlers still assume Cron's GET, remove crons so you do not double-fire, ship to production, confirm in the dashboard Schedules tab, vercel schedules invoke <name>, then optionally move path โ†’ private function for less public surface. Treat every handler as at least once and dedupe on execution ID + your own keys.

Before / after shape (illustrative):

{
  "crons": [{ "path": "/api/jobs/nightly", "schedule": "0 3 * * *" }]
}
{
  "schedules": {
    "nightly": {
      "path": "/api/jobs/nightly",
      "schedule": "0 3 * * *",
      "requestMethod": "GET"
    }
  }
}

When agents need Schedules

Replace tight polling with enqueue + wake at time: dynamic Schedules.create against a Queue topic gets you a follow-up without holding a function open. It does not replace durable logs - see durable AI agents - but it buys IANA time zones and retries on the queue side where Cron only gave you a naked HTTP GET in UTC.

For CI-shaped problems (Turborepo checks, GitHub-only triggers), read Vercel CI vs GitHub Actions - that is not what Schedules fixes.

Want nightly digests, agent follow-ups, or cleanup jobs wired cleanly on a Next.js/Vercel stack without duct tape in vercel.json?

When to wait (or stay on Cron Jobs)

  • UTC-only crons + CRON_SECRET on a path are enough, and you do not need runtime schedules - Cron Jobs still do that; Schedules is just where new knobs ship.
  • Public beta โ‡’ read changelog when upgrading - limits and semantics move.
  • GitHub/macOS/release automation stays in Actions; Schedules trigger Vercel workloads.

Site context: joancomadran.dev is Next.js on Vercel with no vercel.json crons/schedules here - so this is a field guide, not a migration diary for this repo.

FAQ

When did Vercel Schedules go to public beta?

5 November 2026 (changelog); product post 4 November 2026 (blog). Cron Jobs keep working; migration exists - checked 6 November 2026.

Do path-based Schedules use GET like Cron Jobs did?

Default is POST for path schedules; Cron used GET. Set "requestMethod": "GET" when porting unless you switch the handler to POST (migration guide).

What does Schedules pricing look like on Pro as of 6 November 2026?

Changelog + limits (6 November 2026): marginal rates from $5/1M runs and $10/1M creations on Pro/Enterprise; 10k/100k schedules/team on Pro/Enterprise; Hobby 500 creates + 5k runs/month included.

Which schedule targets get automatic retries?

Function + path: no auto-retry. Queue topic: retries. Still idempotent - duplicates possible; use execution ID (limits, 6 November 2026).

About the author

I'm Joan Comadran, an industrial engineer turned AI engineer and full-stack developer in Barcelona. I build Next.js on Vercel (this site) and write about agents and tools - see durable AI agents and Vercel CI vs GitHub Actions. I have not migrated Schedules in this repo; claims above cite Vercel docs dated 6 November 2026 and what this codebase contains. For schedules, queues, and agent-shaped products, that's what I do.

Originally published on joancomadran.dev. I'm Joan, an AI engineer in Barcelona โ€” work with me.

๐Ÿ“ฐ Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes โ€” full credit and traffic to the original publisher.