Edit on val.town ↗

Migrate crons

Use this as a reference, not a required sequence. Adapt the approach and code to suit the app and the user’s needs.

Read the original interval settings and handler. Record its timezone, frequency, last successful run, and effects: emails, API calls, or database writes.

Like Val Town, Cloudflare Cron Triggers use UTC. An elapsed interval is not necessarily equivalent to a wall-clock cron expression.

Put the work in a function called by a Worker scheduled() handler. Configure its cron expression in Wrangler:

{
  "triggers": { "crons": ["0 * * * *"] }
}

This example runs hourly, at minute zero, UTC. Use the app’s actual schedule.

export default {
  async scheduled(event, env, ctx) {
    await runJob(env, event.scheduledTime);
  },
};

Implement runJob with the migrated bindings and secrets. If the old job used its last-run timestamp, preserve that state in durable storage; it is not passed automatically by Cloudflare.

Make retries safe: record processed IDs or completed work so a repeated run does not resend messages or duplicate charges. If runs may overlap, coordinate them with durable state.

Check current execution limits. Use Queues or Workflows if the job needs managed retries or longer, multi-step execution.

Test the handler locally with scheduled-event testing, using disposable data or controlled recipients.

Disable the Val Town schedule before enabling Cloudflare’s. Schedule changes can take time to propagate; verify an actual scheduled run and its effects in production. Record the last successful run and report failures. A deployment alone does not prove the job ran.

Last updated