Cloudflare Workers can be scheduled to run on a cron trigger, allowing you to automate tasks without needing to poll an endpoint.

Let’s see this in action. Imagine you have a Worker script that needs to run daily to clean up old database entries. Instead of setting up a separate server to trigger this Worker every day, you can configure a cron trigger directly within Cloudflare.

Here’s a simplified Worker script:

// workers/cron-cleanup.js
export default {
  async scheduled(event, env, ctx) {
    console.log(`Cron job triggered: ${event.cron}`);
    // Your cleanup logic here
    // For example:
    // await env.YOUR_KV_NAMESPACE.delete("old-data-*");
    console.log("Cleanup complete.");
  },
  async fetch(request, env, ctx) {
    return new Response("Worker is running!");
  }
};

To make this script run on a schedule, you’ll use the wrangler.toml configuration file. You define a cron_triggers section, specifying the cron expression and the Worker’s cron handler function.

# wrangler.toml
name = "scheduled-worker"
main = "src/index.js" # or wherever your worker is located
compatibility_date = "2023-10-26"

[triggers]
crons = [
  { cron = "0 0 * * *", id = "daily_cleanup" }, # Run at midnight every day
  { cron = "*/15 * * * *", id = "fifteen_minute_check" } # Run every 15 minutes
]

When the scheduled function in your Worker script is invoked by a cron trigger, the event object contains information about the trigger, including event.cron, which will be the cron expression that matched. The id in wrangler.toml is a label you assign to the trigger, useful for distinguishing multiple scheduled tasks within the same Worker.

The core problem this solves is the need for a reliable, serverless way to execute code at specific intervals. Before cron triggers, you’d typically rely on external services or EC2 instances to poll your Worker’s endpoint or send requests to an external scheduler. This adds complexity, cost, and potential points of failure. With Cloudflare’s built-in cron triggers, the scheduling is managed by Cloudflare’s global network, ensuring high availability and reducing operational overhead.

Internally, Cloudflare’s cron trigger mechanism monitors the defined schedules. When a cron expression matches the current time, Cloudflare invokes the specified scheduled function within your Worker. This invocation is similar to a regular fetch request in terms of how the Worker environment is set up, providing access to env (bindings like KV namespaces, R2 buckets, etc.) and ctx (for managing background tasks or durable objects).

The exact levers you control are the cron expressions themselves and the ids you assign. Cron expressions are a standard way to define recurring schedules. For example:

  • 0 0 * * *: Every day at midnight.
  • */15 * * * *: Every 15 minutes.
  • 0 9 * * 1-5: Every weekday (Monday to Friday) at 9 AM.
  • 0 0 1 * *: On the first day of every month at midnight.

You can have multiple cron triggers defined for a single Worker, each with its own cron expression and id. Your scheduled function will be called for each matching trigger, and you can use event.cron to differentiate which schedule fired if you need specific logic for each.

The most surprising thing about Cloudflare Workers cron triggers is that they can handle very granular schedules, down to the minute, and they are managed by Cloudflare’s edge infrastructure. This means your scheduled jobs run without you provisioning or managing any servers, and they benefit from Cloudflare’s global distribution. You can even use cron triggers with Durable Objects to ensure that scheduled tasks are executed reliably, even if your Worker instances crash or restart, by coordinating the execution within a Durable Object.

The next concept you’ll likely encounter is managing the state and concurrency of your scheduled tasks, especially when dealing with multiple triggers or ensuring that a long-running cron job doesn’t interfere with regular HTTP requests to your Worker.

Want structured learning?

Take the full Cloudflare course →