Heroku Scheduler vs Posthook
Compare Heroku Scheduler and Posthook for scheduled tasks. Heroku Scheduler runs commands at three fixed intervals with best-effort reliability. Posthook schedules API calls at any time with guaranteed delivery, retries, and tracking.
Last updated: March 30, 2026
Heroku Scheduler runs commands on one-off Heroku dynos at three fixed intervals: every 10 minutes, every hour, or every day. It is a free add-on, configured through a web UI, with no API, no retries, and no execution history. Heroku’s own documentation describes it as “best effort” and recommends a custom clock process for anything critical.
Posthook is a managed scheduling service. You schedule a hook via API — specifying any future time, a target endpoint, and an optional payload — and Posthook handles persistence, delivery, retries, and observability. For recurring work, Sequences replace Heroku Scheduler’s fixed intervals with calendar-based scheduling, DST handling, and config-as-code.
Posthook replaces Heroku Scheduler for both one-off and recurring scheduling. The only exception is if your tasks are CLI commands (rake tasks, management scripts) that are not exposed as HTTP endpoints — those would need to be wrapped in a route first.
At a glance
| Dimension | Heroku Scheduler | Posthook |
|---|---|---|
| Scheduling model | 3 fixed intervals (10 min, hourly, daily) via web UI | Any future time via API — postAt (UTC), postAtLocal + timezone (DST), postIn (relative delay) |
| Recurring scheduling | Same 3 intervals, no other options | Sequences with calendar scheduling, onDays/onDates, DST handling, dependency graphs, config-as-code |
| Execution model | Runs a command on a one-off dyno | Delivers HTTP POST or WebSocket to your endpoint |
| Dynamic scheduling | None — web UI only, no API | Full API with TypeScript, Python, and Go SDKs |
| Reliability | Best-effort — jobs may be missed or run twice, no SLA | At-least-once delivery with configurable retries |
| Retries on failure | None | Configurable backoff (fixed, exponential, jitter), per-hook overrides |
| Timezone / DST | None | UTC, local timezone with automatic DST handling, relative delays |
| Observability | Heroku logs only — limited retention | Dashboard with per-hook delivery inspection and attempt history |
| Alerting | None | Per-endpoint anomaly detection with email, Slack, and webhook notifications |
| Execution history | None — no record of past runs | Full delivery log with status, response body, and timing for every hook |
| Incident response | None | Bulk retry, cancel, or replay filtered by time range, endpoint, or sequence |
| Version control | Web UI only — not in source control, not automated with deploys | API-driven and config-as-code — version-controllable, testable, programmable |
| Platform dependency | Heroku only | Any hosting provider |
| Cost | Free add-on; dyno costs Eco $5, Basic $7, Standard-1x $25, Standard-2x $50/mo | Free tier (1K hooks/mo), Launch $39/20K, Growth $99/100K |
How Heroku Scheduler works
Heroku Scheduler is a free add-on that ships with every Heroku app. You configure it through the Heroku dashboard: type a command, pick one of three intervals, and save. Heroku spins up a one-off dyno, runs your command, and shuts the dyno down.
This model has real strengths:
- Zero configuration. Add the add-on, type a command, pick an interval. No code changes, no API integration, no SDK.
- Free add-on. The only cost is the dyno time for each run — and if you are already paying for dynos, the marginal cost is predictable.
- Runs arbitrary commands. Any command your app can execute —
rake db:cleanup,python manage.py send_digests,node scripts/sync.js. No HTTP endpoint required. - Familiar to every Heroku developer. Ubiquitous, well-understood, minimal learning curve.
The limits are also well understood:
- Best-effort execution. Heroku’s own docs state that Scheduler is best-effort and that jobs may occasionally be missed or run more than once. There is no SLA.
- Three intervals only. 10 minutes, hourly, or daily. No other options. No per-event scheduling, no arbitrary timestamps, no “run this 14 days from now.”
- No retries. If a job fails, it is simply gone. There is no retry mechanism, no failure notification, and no record that the run was attempted.
- No execution history. There is no way to verify whether a scheduled job ran, succeeded, or failed. The only evidence is in Heroku’s application logs, which have limited retention.
- Web UI only. Schedules are configured through the dashboard — not in version control, not deployable via CI/CD, not programmable. The Judoscale team (a Heroku autoscaling add-on vendor) published a detailed critique of this limitation: schedules drift from what is in source control, new developers do not know what is configured, and there is no way to automate schedule management across environments.
- No API. You cannot create, modify, or delete schedules programmatically.
For non-critical recurring tasks where these constraints are acceptable, Heroku Scheduler is simple and free. That is a genuine advantage.
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.
import Posthook from "@posthook/node";
const posthook = new Posthook("phk_...");
// Schedule a one-off delivery at a specific time
await posthook.hooks.schedule({
path: "/hooks/expire-trial",
postAt: "2026-04-06T00:00:00Z",
data: { trialId: "trial_xyz" },
});
// Schedule relative to now
await posthook.hooks.schedule({
path: "/hooks/send-reminder",
postIn: "24h",
data: { userId: "user_abc" },
});
// Schedule in a user's local timezone (DST-safe)
await posthook.hooks.schedule({
path: "/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, checks state, and decides what to do:
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 });
}
Key capabilities:
- Three scheduling modes —
postAtfor exact UTC timestamps,postAtLocal+ timezone for user-local scheduling with automatic DST handling,postInfor relative delays up to 365 days - 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
- 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. Heroku Scheduler kills tasks that exceed their interval; async hooks let your application complete on its own timeline.
- Sequences — recurring workflows with calendar scheduling, dependency graphs, and config-as-code via
posthook.toml
The platform context
In February 2026, Salesforce announced that Heroku is moving to sustaining engineering. The platform will continue to operate, but it is unlikely to receive significant new features. Heroku Scheduler has not received feature updates in years; that trajectory is unlikely to change.
This is not a reason to panic, but it is relevant context for teams evaluating their tooling. Platform-dependent add-ons carry the same trajectory as the platform itself. Posthook works with Heroku today — it delivers to any HTTPS endpoint — and it works with whatever platform comes next.
When Posthook replaces Heroku Scheduler
Posthook replaces Heroku Scheduler for both categories of work it handles:
One-off future scheduling. Heroku Scheduler does not support this at all. There is no way to say “run this task 14 days from now” or “send this reminder at 9am Tuesday in the user’s timezone.” With Posthook, each event creates its own timer via a single API call.
Recurring scheduling. Heroku Scheduler’s three fixed intervals — 10 minutes, hourly, daily — are replaced by Sequences. Sequences offer calendar-based scheduling with onDays and onDates, DST handling across timezone transitions, dependency graphs between steps, per-step retry overrides, and config-as-code via posthook.toml with diff, validate, and apply across environments.
The only scenario where Heroku Scheduler remains necessary is for CLI commands that are not exposed as HTTP endpoints. If your scheduled work is a rake task or management command that cannot be called via HTTP, Heroku Scheduler (or a custom clock process) is still the tool for the job. But if those tasks can be wrapped in a route — and most can — Posthook replaces Scheduler entirely.
When to choose each
Keep Heroku Scheduler when:
- Your tasks are CLI commands (rake tasks, management scripts) not exposed as HTTP endpoints
- The tasks are non-critical and you can tolerate occasional missed or duplicate runs
- You only need one of three intervals (10 min, hourly, daily)
- You do not need execution history, failure alerting, or programmatic scheduling
Choose Posthook when:
- Reliability matters — missed jobs are not acceptable
- You need dynamic scheduling from application code — per-user reminders, expiration checks, follow-ups
- You need scheduling precision beyond three fixed intervals — any future timestamp, any timezone
- You need retries when a job fails
- You need execution history and delivery tracking
- You want observability, anomaly detection, and alerting
- You need recurring scheduling with more flexibility than 10min/hourly/daily — Sequences with calendar scheduling, DST, and config-as-code
- You want version-controllable, API-driven scheduling instead of a web UI
- You are migrating off Heroku or want platform-independent tooling
Frequently asked questions
Ready to get started?
Create your free account and start scheduling hooks in minutes. No credit card required.