Vercel Cron vs Posthook: Static vs Dynamic Scheduling
Compare Vercel Cron Jobs and Posthook for scheduling on Next.js. Vercel Cron handles fixed recurring tasks with no retries. Posthook handles both dynamic and recurring scheduling with delivery tracking, retries, and anomaly detection.
Last updated: March 24, 2026
Vercel Cron Jobs and Posthook solve different scheduling problems. Vercel Cron handles fixed recurring tasks defined at deploy time — a cron expression in vercel.json that fires on a schedule you know in advance. Posthook handles dynamic scheduling decided at runtime — a user signs up and you schedule a reminder for 24 hours from now, or a trial starts and you schedule an expiration check for 14 days out.
The distinction matters because most scheduling work in a production application is not fixed-cadence. It is event-driven: something happens in your app, and you need something else to happen later. “Send this user a reminder in 24 hours” is one API call with Posthook and fundamentally impossible with Vercel Cron. “Expire this trial 14 days after signup” requires a polling workaround with Vercel Cron — a cron job scanning a database every minute — and a single scheduling call with Posthook. “Retry a failed payment next Tuesday at 10am in the user’s timezone” is not expressible with Vercel Cron at all.
If your only scheduling need is a handful of fixed recurring tasks and you want zero configuration, Vercel Cron is the simpler choice. But once scheduling decisions depend on runtime events, Posthook is the tool that fits the problem. And for recurring work, Posthook Sequences offer more power and reliability than Vercel Cron Jobs — calendar scheduling with DST handling, dependency graphs between steps, and config-as-code with diff and apply.
At a glance
| Dimension | Vercel Cron | Posthook |
|---|---|---|
| Scheduling model | Static cron expressions in vercel.json, set at deploy time | Dynamic API calls at runtime — schedule anything when the event happens |
| One-time future scheduling | Not supported | First-class — postAt (UTC timestamp), postAtLocal + timezone (DST), postIn (relative delay) |
| Dynamic scheduling | Requires redeployment to change schedules | Core design — schedule from any API route or server action |
| Recurring scheduling | Cron expressions (UTC only) | Sequences with calendar scheduling, DST handling, dependency graphs, onDays/onDates, config-as-code |
| Delivery target | Your own Vercel routes only | Any HTTP endpoint or WebSocket |
| Delivery method | HTTP GET | HTTP POST (or WebSocket) |
| Retries on failure | None — failed invocations are not retried | Configurable backoff (fixed, exponential, jitter), per-hook overrides |
| Timezone / DST | UTC only | UTC, local timezone with automatic DST handling, relative delays |
| Precision | Hobby: up to 59 minutes late. Pro: within the minute | Second-level precision |
| Observability | Function logs — 1-hour retention (Hobby), 1-day (Pro) | Dashboard with per-hook delivery inspection and attempt history |
| Alerting | None | Per-endpoint anomaly detection with email, Slack, and webhook notifications |
| Incident response | None — no replay, no bulk retry | Bulk retry, cancel, or replay filtered by time range, endpoint, or sequence |
| Delivery guarantee | Docs warn cron events may fire more than once | At-least-once delivery — duplicates are rare but possible; handlers should be idempotent |
| Infrastructure | Zero — built into Vercel | API key + endpoint |
| Cost | Included with Vercel plan (counts as function invocations) | Free tier (1K hooks/mo), Launch $39/20K, Growth $99/100K |
| Best fit | Fixed recurring tasks on known schedules — daily cleanup, cache warming, periodic sync | Dynamic per-event scheduling — reminders, expirations, retries, follow-ups, timezone-aware delivery |
How Vercel Cron Jobs work
Vercel Cron Jobs are built into the Vercel platform. You define cron expressions in vercel.json, and Vercel triggers an HTTP GET to a route in your production deployment on the specified schedule. The feature is built on Amazon EventBridge Scheduler.
{
"crons": [
{
"path": "/api/daily-cleanup",
"schedule": "0 8 * * *"
}
]
}
This is a clean model for simple recurring tasks:
- Zero configuration cost — add the cron expression, deploy, and it works. No separate service, no API key, no billing relationship.
- Native Vercel integration — cron jobs appear in the Vercel dashboard. As of March 2026, you can manually trigger a cron job from the deployment summary.
- 100 cron jobs per project on all plans (raised January 2026).
- Built on reliable infrastructure — Amazon EventBridge Scheduler handles the scheduling under the hood.
The limits are worth understanding clearly:
- Hobby plan: once per day maximum frequency, and invocations can arrive up to 59 minutes late.
- Pro plan: once per minute frequency, within the specified minute.
- Production deployments only — cron jobs do not run in preview or development environments.
- No retries — if a cron invocation fails, Vercel does not retry it. The failure appears in function logs and disappears after 1 hour (Hobby) or 1 day (Pro).
- UTC only — no timezone or DST support.
- No programmatic creation — schedules are defined in
vercel.jsonand require a redeployment to change. - Possible duplicate execution — Vercel’s documentation warns that cron events may be delivered more than once.
For fixed-cadence tasks where these constraints are acceptable — daily reports, periodic cache warming, hourly data sync — Vercel Cron is the right tool. It is simple and free.
The dynamic scheduling gap
The limitation is not that Vercel Cron is unreliable at what it does. The limitation is that most scheduling work in a production application is not fixed-cadence.
Consider three common patterns:
Send a reminder 24 hours after signup. Each user signs up at a different time. You need a timer for each signup event, not a single recurring schedule. Vercel Cron cannot express this.
Expire a trial 14 days after activation. Each trial starts on a different date. With Vercel Cron, the common workaround is a cron job that runs every minute, queries the database for trials that should have expired, and processes them. This is the polling anti-pattern — it works, but it scales poorly, wastes compute on empty runs, and becomes its own operational surface: what happens when the query is slow, or the function times out, or the database is temporarily unreachable? The cron job has no retry logic, so the expired trials sit unprocessed until the next run.
Retry a failed payment next Tuesday at 10am in the user’s timezone. This requires scheduling a specific future time, in a specific timezone, with DST handling. Vercel Cron is UTC-only and has no concept of per-event scheduling or timezone-aware delivery.
These are not edge cases. They are the core scheduling problems in most SaaS applications. Vercel Cron was designed for a different job — and it does that job well.
How Posthook works
Posthook is a managed scheduling service. You schedule a hook via API — specifying a target endpoint, a delivery time, and an optional payload — and Posthook handles persistence, delivery, retries, and observability.
For a Next.js developer, the integration looks like this:
import Posthook from "@posthook/node";
const posthook = new Posthook("phk_...");
// Schedule a reminder 24 hours from now
await posthook.hooks.schedule({
path: "/api/hooks/send-reminder",
postIn: "24h",
data: { userId: "user_abc", type: "onboarding" },
});
// Schedule a trial expiration at a specific time
await posthook.hooks.schedule({
path: "/api/hooks/expire-trial",
postAt: "2026-04-06T00:00:00Z",
data: { trialId: "trial_xyz" },
});
// Schedule in the user's local timezone (DST-safe)
await posthook.hooks.schedule({
path: "/api/hooks/payment-retry",
postAtLocal: "2026-03-31T10:00:00",
timezone: "America/New_York",
data: { paymentId: "pay_123" },
});
Your handler receives the delivery as an HTTP POST and decides what to do:
// app/api/hooks/expire-trial/route.ts
export async function POST(req: Request) {
const { data } = await req.json();
const trial = await db.trials.findById(data.trialId);
// Handler checks state — act or skip
if (!trial || trial.status !== "active") {
return Response.json({ skipped: true });
}
await db.trials.expire(trial.id);
await sendTrialExpiredEmail(trial.userId);
return Response.json({ expired: true });
}
No polling. No cron job scanning a database. Each event creates its own timer, and Posthook delivers it at the right time.
Key capabilities for Next.js teams:
- Three scheduling modes —
postAtfor exact UTC timestamps,postAtLocal+ timezone for user-local scheduling with automatic DST handling,postInfor relative delays - Configurable retries — fixed, exponential, or jitter backoff with per-hook overrides at scheduling time
- Built-in anomaly detection — per-endpoint failure rate tracking against historical baselines, with alerts via email, Slack, or webhook when failure rates spike
- Incident response — bulk retry, cancel, or replay failed hooks filtered by time range, endpoint key, or sequence ID
- Async hooks for reliable long-running work — your endpoint returns 202 Accepted immediately, offloads processing, and calls back via ack/nack URLs when done. Configurable timeouts up to 3 hours. Your Vercel function handles the handoff quickly; the actual work runs wherever you need it to
- Sequences — recurring workflows with calendar scheduling, dependency graphs, and config-as-code via
posthook.toml
Tradeoffs
Where Vercel Cron wins
- Zero configuration. Add a cron expression to
vercel.jsonand deploy. No API key, no SDK, no additional service to integrate. - No additional cost. Cron invocations count as Vercel function calls. There is no separate billing relationship.
- No external dependency. Scheduling lives with your deployment. No third-party service to evaluate, onboard, or monitor.
- Native ecosystem integration. Cron jobs appear in the Vercel dashboard, can be triggered manually from the deployment summary, and work within the Vercel deployment model.
- Simple mental model. If the schedule is “run this every day at 8am UTC,” a cron expression is the most direct way to express it.
Where Posthook wins
- Dynamic scheduling. Schedule anything at runtime based on application events. No redeployment, no polling, no scanning a database for work. Each event creates its own timer.
- Retries. Vercel Cron has zero retry capability — if an invocation fails, it is gone. Posthook retries with configurable backoff and per-hook overrides. Every attempt is logged with status, response, and error details.
- Timezone-aware scheduling.
postAtLocalwith a timezone handles DST transitions automatically. Vercel Cron is UTC-only — no concept of “10am in the user’s timezone.” - Observability and alerting. Dashboard with per-hook delivery inspection, attempt history, and per-endpoint anomaly detection with multi-channel alerts. Vercel Cron function logs expire after 1 hour on Hobby and 1 day on Pro.
- Incident response. One API call retries all failed hooks in a time range. With Vercel Cron, a missed invocation is simply missed — there is no replay mechanism.
- Delivery to any endpoint. Vercel Cron sends HTTP GET to your own Vercel routes. Posthook delivers HTTP POST (or WebSocket) to any endpoint — your own routes, external services, or private networks.
- Precision. Second-level delivery precision. Vercel Cron Hobby can arrive up to 59 minutes late.
- Async hooks. Your endpoint returns 202 immediately, offloads the work, and calls back when done — with up to 3-hour timeouts. The Vercel function handles the handoff quickly; the actual processing runs wherever makes sense for your architecture.
When Posthook replaces Vercel Cron entirely
Posthook Sequences cover everything Vercel Cron does for recurring work — and more:
- Calendar scheduling with DST handling. Sequences schedule by calendar time in any timezone. Vercel Cron is UTC-only, so a “9am daily” job drifts by an hour across DST transitions.
- Flexible recurrence patterns.
onDays,onDates, and negative dates (e.g.,-1for last day of month) express schedules that cron syntax cannot. - Dependency graphs between steps. Multi-step recurring workflows where step B runs after step A completes. Vercel Cron has no concept of step ordering or dependencies.
- Per-delivery retries. Every Sequence step retries on failure with configurable backoff. Vercel Cron does not retry at all.
- Delivery tracking and anomaly detection. Every Sequence delivery is tracked with status, response, and attempt history. Anomaly detection alerts you when failure rates change. Vercel Cron has short-lived function logs and no alerting.
- Config-as-code. Define Sequences in
posthook.tomlwith diff, validate, and apply across environments. Vercel Cron expressions live invercel.jsonand require redeployment to change — but there is no diff, no validation, and no multi-environment support.
The only reason to keep Vercel Cron alongside Posthook is free-tier quota conservation. If you have simple daily tasks and want to save your Posthook hook quota for dynamic scheduling, leaving those tasks on Vercel Cron is a reasonable choice. But it is an optimization, not a capability gap.
When to choose each
Choose Vercel Cron when:
- You need a handful of fixed recurring tasks on a known schedule
- The schedule is defined at deploy time and rarely changes
- You are on Vercel and want zero additional configuration
- Hobby-tier daily precision or Pro-tier minute precision is acceptable
- You do not need retries, delivery tracking, or failure alerting
- The tasks call your own Vercel routes, not external endpoints
Choose Posthook when:
- Scheduling decisions happen at runtime based on user actions or application events
- You need one-time future scheduling — “send this in 24 hours,” “expire this in 14 days”
- You need per-user or per-event scheduling at any scale
- You need retries with backoff when a delivery fails
- You need timezone-aware scheduling with DST handling
- You need observability, failure alerting, or delivery inspection
- You want recurring workflows with more power than cron expressions — calendar scheduling, dependency graphs, config-as-code
- You need to deliver to external endpoints, not just your own Vercel routes
Frequently asked questions
Ready to get started?
Create your free account and start scheduling hooks in minutes. No credit card required.