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:
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:
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
- Cron Triggers - Expression syntax and worker usage
- Queues - Process background jobs
- Database - Store data with SQLite
How is this guide?
Last updated on