Cron

Schedule crons with Node, Cloudflare, or Vercel.

Use Cron to run recurring work such as digests, cleanup tasks, syncs, and reports from a schedule instead of a request or queue message.

Define crons in server/crons/** with defineCron(schedules, handler), then trigger one manually with runCron().

Getting started

Install the package

Terminal
pnpm add https://pkg.pr.new/vite-hub/vitehub/@vitehub/cron@main

Configure a provider

Set the top-level cron key for the scheduler backend.

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@vitehub/cron/nuxt'],
  cron: {
    provider: 'node',
  },
})

Define a cron

Declare the schedule next to the cron. Start with a plain cron string. Move to schedule objects when you need Node-specific controls such as timezone or maxRuns.

server/crons/daily-digest.ts
export default defineCron(['0 12 * * 1'], async (rawEvent) => {
  const event = await readValidatedEvent(rawEvent, (payload) => ({
    headlines: Array.isArray(payload?.headlines) ? payload.headlines : [],
  }))
  const headlines = Array.isArray(event.payload?.headlines) ? event.payload.headlines : []

  return {
    count: headlines.length,
  }
})

Run the same cron manually

Manual execution uses the same handler. This is useful for preview routes, backfills, and admin actions.

server/api/crons/digest.post.ts
import { readBody } from 'h3'
import { runCron } from '@vitehub/cron'

export default defineEventHandler(async (event) => {
  const body = await readBody(event)

  return await runCron('daily-digest', {
    payload: body,
  })
})
Node Cron
Configure in-process scheduling with Croner and Node-only schedule controls.
Cloudflare Cron
Configure Cloudflare-triggered schedules for your crons.
Vercel Cron
Generate Vercel cron config from discovered crons.

Public API

FunctionUse it for

| defineCron(schedules, handler) | Register one named cron under server/crons/** and declare its schedules. |

| runCron(name, { payload?, context? }) | Trigger that cron manually from a route, task, or webhook. | | startScheduleRunner(options?) | Start the in-process Node scheduler for all registered crons. | | getCronsForExpression(cron) | Return the cron names registered under a given cron expression. | | runCronsForExpression(cron, { payload?, context? }) | Run every cron registered under a given cron expression. |

Type reference

CronEvent<TPayload>

The handler receives a CronEvent object with these fields:

FieldTypeDescription
namestringThe cron name derived from the file path.
payloadTPayloadData passed via runCron() or the scheduled trigger.
contextCronContextExecution context from the runtime.

The handler can return any value or nothing at all. ViteHub does not enforce a return type.

CronDefinitionOptions

The schedules array passed to defineCron() accepts:

OptionTypeDescription
schedulesArray<string | CronSchedule>One or more cron expressions.

Each schedule can be a plain five-field cron string like '0 12 * * 1' or a CronSchedule object for Node-specific controls:

FieldTypeDescription
cronstringFive-field cron expression (required).
timezonestringIANA timezone. Node provider only.
overlap'allow' | 'prevent'Overlap behavior. Node provider only.
startAtstringISO date to start scheduling. Node provider only.
stopAtstringISO date to stop scheduling. Node provider only.
maxRunsnumberMaximum number of runs. Node provider only.

Configure provider and cron options

Cron configuration is intentionally small:

  • Top-level cron config selects the scheduler provider for the app.
  • createCron(options?)(handler) configures one cron file through an options object.
  • defineCron(schedules, handler) configures one cron file by putting schedules in the first argument. ::
  • defineCron(schedules, handler) configures one cron file by putting schedules in the first argument.

runCron() is only for manual execution. It does not define schedules or provider behavior.

nuxt.config.ts
export default defineNuxtConfig({
  cron: {
    provider: 'vercel',
  },
})
server/crons/daily-digest.ts
export default defineCron(['0 12 * * 1'], async (event) => {
  return {
    count: Array.isArray(event.payload?.headlines) ? event.payload.headlines.length : 0,
  }
})
Each provider adds its own scheduling behavior and sub-features. Use the provider pages in the sidebar for provider-specific schedule support, generated routes, secrets, and runtime helpers.