cron-scheduling — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited cron-scheduling (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
What it is: Cron scheduling is the backend discipline of starting recurring work on a time-based schedule while making the resulting execution safe, observable, and recoverable.
Mental model: A schedule expression only creates an alarm. Production scheduling also needs an authenticated entrypoint, a durable worker or workflow target, an idempotency key for the scheduled window, overlap prevention, and monitoring that detects missed starts, failed completions, and duplicate invocations.
Why it exists: Time-based jobs fail outside the normal request path. They can run twice, not retry, overlap with themselves, execute in UTC instead of the expected local time, or disappear into logs without alerting. The skill turns those hidden failure modes into explicit design checks.
What it is NOT: It is not general background-job queue design, event-schema design, webhook ingestion, browser live-update transport, or debugging an isolated worker failure. It owns the schedule-trigger boundary and composes with those skills after work is triggered.
Adjacent concepts: Background jobs, durable workflows, observability, webhook integration, distributed locks, idempotency, and retry classification.
One-line analogy: Cron scheduling is an alarm clock wired to a factory: the alarm rings, but the factory still needs a work order, lock, status board, and missed-alarm monitor.
Common misconception: The common mistake is believing the cron expression is the design. The expression is only the trigger; the production design is the reliability envelope around the trigger.
What is this skill? This skill provides cron job architecture patterns for web applications: Inngest schedule integration, Vercel Cron configuration, retry logic, monitoring and alerting for failed crons, and idempotency requirements. Load when designing scheduled tasks, configuring cron triggers, debugging missed or duplicate executions, or implementing monitoring for recurring jobs.
A cron that runs twice is worse than a cron that doesn't run. Idempotency is not optional.
This skill covers cron expression syntax and scheduling precision, Vercel Cron configuration (vercel.json cron routes), Inngest scheduled function patterns (cron triggers vs event-driven), idempotency guarantees for scheduled jobs, retry and failure handling for cron-triggered work, monitoring and alerting for missed or failed cron executions, timezone handling in cron schedules, and the decision framework for choosing between Vercel Cron, Inngest schedules, and external cron services.
Cron jobs are the most deceptively simple infrastructure in web applications. The expression 0 9 * * * looks trivial, but the implementation must handle: what happens when the job runs twice (deploy overlap), what happens when the job fails silently (no monitoring), what happens when the job takes longer than the interval (overlap), and what happens at DST transitions (timezone drift). Every anti-pattern in this skill was observed in production. The skill exists because agents routinely create cron schedules without idempotency, without monitoring, and without considering the failure modes that only surface under real-world conditions.
| Platform | Max Duration | Cold Start | Retry Built-in | Monitoring | Best For |
|---|---|---|---|---|---|
| Vercel Cron | Same as the invoked Vercel Function's maxDuration | Yes | No | Basic logs | Lightweight triggers that dispatch to background jobs |
| Inngest Cron | Configurable (step functions) | No (warm) | Yes (built-in) | Dashboard + webhooks | Complex scheduled workflows with retry and state |
| External (e.g., cron-job.org) | N/A (HTTP trigger) | Depends on target | No | External | When the app has no built-in cron capability |
Key architectural rule: Vercel Cron should trigger work, not perform work. The cron route should dispatch an Inngest event or enqueue a background job, then return 200 immediately. Never put long-running logic directly in a Vercel Cron handler.
// vercel.json
{
"crons": [
{
"path": "/api/cron/daily-digest",
"schedule": "0 9 * * *"
},
{
"path": "/api/cron/sync-orders",
"schedule": "*/15 * * * *"
}
]
}Security: When the project defines CRON_SECRET, Vercel sends it as an Authorization header with a Bearer prefix. Always verify that header in the route handler to prevent unauthorized execution:
// api/cron/daily-digest/route.ts
export async function GET(request: Request) {
const authHeader = request.headers.get('authorization');
if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {
return new Response('Unauthorized', { status: 401 });
}
// Dispatch work, do not perform work here
await inngest.send({ name: 'cron/daily-digest.triggered' });
return new Response('OK', { status: 200 });
}// Inngest cron function — preferred for complex scheduled work
import { cron } from "inngest";
export const dailyDigest = inngest.createFunction(
{
id: 'daily-digest',
retries: 3,
concurrency: { limit: 1 }, // Prevent overlap
triggers: [cron('TZ=UTC 0 9 * * *')],
},
async ({ step }) => {
const orgs = await step.run('fetch-orgs', async () => {
return db.query('SELECT id FROM organizations WHERE digest_enabled = true');
});
for (const org of orgs) {
await step.run(`send-digest-${org.id}`, async () => {
return sendDigestEmail(org.id);
});
}
}
);Every cron job must be idempotent: running it twice with the same inputs produces the same result. This is not defensive programming; it is a hard requirement because:
Pattern: Use an idempotency key based on the scheduled execution window:
const idempotencyKey = `digest-${orgId}-${format(new Date(), 'yyyy-MM-dd')}`;
const existing = await db.query(
'SELECT 1 FROM cron_executions WHERE idempotency_key = $1',
[idempotencyKey]
);
if (existing.rows.length > 0) {
return { skipped: true, reason: 'already executed' };
}
// Execute, then record
await db.query(
'INSERT INTO cron_executions (idempotency_key, executed_at) VALUES ($1, NOW())',
[idempotencyKey]
);| Expression | Meaning | Common Use |
|---|---|---|
* * * * * | Every minute | Health checks (use sparingly) |
*/5 * * * * | Every 5 minutes | Order sync polling |
*/15 * * * * | Every 15 minutes | Data refresh, cache warm |
0 * * * * | Every hour, on the hour | Hourly reports |
0 9 * * * | Daily at 09:00 UTC | Daily digest |
0 9 * * 1 | Monday at 09:00 UTC | Weekly summary |
0 0 1 * * | First day of month, midnight | Monthly rollup |
Timezone rule: Vercel Cron schedules are UTC. Inngest cron triggers support an optional TZ=<zone> prefix. If the user expects "9am Eastern", either use a scheduler that supports the intended timezone or compute the UTC offset and account for DST transitions. Document the intended local time next to every cron expression.
A cron job that fails silently is worse than no cron job. Implement monitoring at three levels:
| Level | What to Monitor | Alert When |
|---|---|---|
| Execution | Did the job start? | No execution within expected window + buffer |
| Completion | Did the job finish? | Execution started but no completion within timeout |
| Result | Did the job produce correct output? | Completion with error status or unexpected result count |
Heartbeat pattern: After each successful cron execution, ping an external heartbeat monitor (e.g., Cronitor, Better Uptime, or a custom endpoint). If the heartbeat is missed, the monitor alerts the team.
// After successful cron execution
await fetch(`${process.env.HEARTBEAT_URL}/cron-daily-digest`, {
method: 'POST',
body: JSON.stringify({ status: 'ok', processedCount: orgs.length }),
});When a cron job takes longer than its interval (e.g., a 15-minute sync that runs every 10 minutes), overlapping executions corrupt data or cause duplicate processing.
Solutions:
concurrency: { limit: 1 } on the functionWhen a cron job fails, it must:
0 9 * * * without a comment explaining the intended local time. When DST shifts, 9am UTC becomes 4am or 5am Eastern, surprising the user.When working in a project with cron scheduling:
vercel.json — Vercel Cron route definitionsapi/cron/ or app/api/cron/ — Cron route handlerscron_executions table (if it exists) — idempotency trackingAfter applying this skill, verify:
CRON_SECRET authorization header| Instead of this skill | Use | Why |
|---|---|---|
| Event-driven job orchestration (not time-based) | background-jobs | Background jobs own worker/queue architecture; this skill owns time-triggered schedules. |
| General background job queue patterns | background-jobs | Job queue architecture is broader than cron-specific scheduling |
| Data synchronization triggered by incoming provider events | webhook-integration | Webhook integration owns inbound event contracts and idempotent ingestion; cron is only one polling trigger. |
| Alert rule design, metrics, and missed-run detection | observability-modeling | Observability owns what to measure and alert on; this skill owns how a time-based check is scheduled and made idempotent. |
Version 1.0.0 -- 2026-03-29. Initial creation.
<!-- skill-graph-context:start (generated — do not edit by hand) -->
Classification
backend-engineeringtrueengineering/schedulingWhen to use
cron-scheduling-skill, cron-job-skill, scheduled-task-skill, vercel-cron-skill, recurring-job-skillNot for
Related skills
observability-modeling, webhook-integration, background-jobsbackground-jobs, real-time-updates, observability-modeling, webhook-integrationConcept
Grounding
hybridhttps://vercel.com/docs/cron-jobs, https://vercel.com/docs/cron-jobs/manage-cron-jobs, https://www.inngest.com/docs/learn/inngest-functions, https://www.inngest.com/docs/reference/typescript/functions/triggers, https://www.inngest.com/docs/functions/concurrency, https://www.inngest.com/docs/reference/typescript/functions/handling-failures, https://www.inngest.com/docs/platform/monitor/observability-metricsKeywords
cron scheduling, cron job, scheduled task, Vercel Cron, Inngest cron, recurring job, idempotent cron, missed cron, cron monitoring, timezone cron<!-- skill-graph-context:end -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.