Ploy
Ploy
Next.js

Cron Triggers

Run scheduled jobs in your Next.js app with Ploy cron triggers.

Cron Triggers

Run recurring jobs — nightly reports, cleanup passes, billing ticks — alongside your Next.js app.

Configuration

Add cron triggers in your ploy.yaml:

ploy.yaml
kind: dynamic
build: pnpm build
out: dist
db:
  DB: default
cron:
  HOURLY_CLEANUP: "0 * * * *"
  EVERY_10_SECONDS: "*/10 * * * * *"

Each key is a trigger name and each value a cron expression. The standard form has 5 fields; a 6-field expression adds a leading seconds field for sub-minute schedules. See Cron Triggers for the full expression syntax.

Scheduled Handler

Export a scheduled handler from your handlers module — app/ploy.ts, or worker/index.ts if you keep it out of the app directory:

worker/index.ts
export default {
	async scheduled(event, env) {
		await env.DB.prepare("DELETE FROM sessions WHERE expires_at < ?")
			.bind(Date.now())
			.run();

		console.log(`Ran ${event.cron} at ${String(event.scheduledTime)}`);
	},
} satisfies Ploy;

The handler receives the same env bindings as your routes, so it can read and write your database, send queue messages, and call the AI gateway.

Use event.cron to tell triggers apart when you declare more than one:

async scheduled(event, env) {
	if (event.cron === "0 * * * *") {
		await runCleanup(env);
		return;
	}

	await runBillingTick(env);
}

Local Development

ploy dev schedules your triggers locally and delivers each one to the app's /ploy-handler route, which initPloyForDev() creates when it is missing. See Background Handlers.

Execution history — including failures and durations — is visible in the dev dashboard at http://localhost:4000, where you can also fire a trigger by hand instead of waiting for its next tick.

Triggers only fire while the dev server is running. A schedule that was due while it was stopped does not catch up.

Next Steps

How is this guide?

Last updated on