Skip to content

Cron Triggers

Last updated View as MarkdownAgent setup

Background

Cron Triggers allow users to map a cron expression to a Worker using a scheduled() handler that enables Workers to be executed on a schedule.

Cron Triggers are ideal for running periodic jobs, such as for maintenance or calling third-party APIs to collect up-to-date data. Workers scheduled by Cron Triggers will run on underutilized machines to make the best use of Cloudflare's capacity and route traffic efficiently.

Cron Triggers execute on UTC time.

Add a Cron Trigger

1. Define a scheduled event listener

To respond to a Cron Trigger, you must add a "scheduled" handler to your Worker.

export default {
	async scheduled(controller, env, ctx) {
		console.log("cron processed");
	},
};
interface Env {}
export default {
	async scheduled(
		controller: ScheduledController,
		env: Env,
		ctx: ExecutionContext,
	) {
		console.log("cron processed");
	},
};
from workers import WorkerEntrypoint

class Default(WorkerEntrypoint):
    async def scheduled(self, controller, env, ctx):
        # All four parameters (self, controller, env, ctx) are required
        print("cron processed")

Refer to the following additional examples to write your code:

2. Update configuration

After you have updated your Worker code to include a "scheduled" event, you must update your Worker project configuration.

Via cloudflare.config.ts

For projects managed with the Cloudflare CLI, add triggers.scheduled() entries to worker.triggers in cloudflare.config.ts:

Select a highlighted line to show its type and description below it.

cloudflare.config.ts
import { defineConfig, triggers } from "cf/config";
import * as entrypoint from "./src/index.ts" with { type: "cf-worker" };
export default defineConfig({ (defineConfig reference)

defineConfigFunctionLink to defineConfig

defineConfig<T extends ConfigInput<CloudflareConfig>>(config: T): T;

Defines the default export of cloudflare.config.ts. Pass a configuration object, a promise that resolves to one, or a function that receives the config context (isPreview and mode) and returns either.

Options (4)
accountId?: string
This is the ID of the account associated with your zone. It can also be specified through the CLOUDFLARE_ACCOUNT_ID environment variable.
complianceRegion?: "public" | "fedramp-high"
The compliance boundary in which commands should operate. When omitted, this can be supplied through CLOUDFLARE_COMPLIANCE_REGION.
worker?: ConfigInput<WorkerConfig>
The Worker defined by this configuration.
containers?: ConfigInput<ContainerConfig>[]
Container applications defined by this configuration.
worker: { (worker reference)

workerOptionalLink to worker

worker?: ConfigInput<WorkerConfig>

The Worker defined by this configuration.

name: "my-worker", (name reference)

nameRequiredLink to name

name: string

The name of your Worker.

entrypoint, (entrypoint reference)

entrypointOptionalLink to entrypoint

entrypoint?: string | WorkerModule

The entrypoint module that will be executed. May be either a path string (e.g. "./src/index.ts") or a module namespace imported with the cf-worker import attribute.

compatibilityDate: "<COMPATIBILITY_DATE>", (compatibilityDate reference)

compatibilityDateRequiredLink to compatibilityDate

compatibilityDate: string

A date in the form yyyy-mm-dd, which will be used to determine which version of the Workers runtime is used. More details at https://developers.cloudflare.com/workers/configuration/compatibility-dates

triggers: [triggers.scheduled({ schedule: "0 * * * *" })], (triggers, scheduled, schedule reference)

triggersOptionalLink to triggers

triggers?: Trigger[]

Event triggers — fetch routes, queue consumers, cron schedules, Email Routing addresses, and raw sockets — that invoke this Worker. Construct entries with triggers.fetch(...), triggers.queue(...), triggers.scheduled(...), triggers.email(...), or triggers.connect(...). For reference, see https://developers.cloudflare.com/workers/wrangler/configuration/#triggers

scheduledBuilderLink to scheduled

scheduled(options: ScheduledTriggerOptions): ScheduledTrigger;

Scheduled (cron) trigger — invokes this Worker on the given schedules. More details here https://developers.cloudflare.com/workers/platform/cron-triggers

Options (1)
schedule: string
A "cron" definition to trigger a Worker's "scheduled" function. Lets you call Workers periodically, much like a cron job. More details here https://developers.cloudflare.com/workers/platform/cron-triggers

scheduleRequiredLink to schedule

schedule: string

A "cron" definition to trigger a Worker's "scheduled" function. Lets you call Workers periodically, much like a cron job. More details here https://developers.cloudflare.com/workers/platform/cron-triggers

},
});

Run cf dev to test the handler locally. Run cf deploy to deploy the configured schedule.

If a Worker is managed with Wrangler, Cron Triggers should be exclusively managed through the Wrangler configuration file.

Refer to the example below for a Cron Triggers configuration:

{
	"triggers": {
		// Schedule cron triggers:
		// - At every 3rd minute
		// - At 15:00 (UTC) on first day of the month
		// - At 23:59 (UTC) on the last weekday of the month
		"crons": [
			"*/3 * * * *",
			"0 15 1 * *",
			"59 23 LW * *"
		]
	}
}
[triggers]
crons = [ "*/3 * * * *", "0 15 1 * *", "59 23 LW * *" ]

You also can set a different Cron Trigger for each environment in your Wrangler configuration file. You need to put the triggers array under your chosen environment. For example:

{
	"env": {
		"dev": {
			"triggers": {
				"crons": [
					"0 * * * *"
				]
			}
		}
	}
}
[env.dev.triggers]
crons = [ "0 * * * *" ]

Via the dashboard

To add Cron Triggers in the Cloudflare dashboard:

  1. In the Cloudflare dashboard, go to the Workers & Pages page.

    Go to Workers & Pages ↗
  2. In Overview, select your Worker > Settings > Triggers > Cron Triggers.

Supported cron expressions

Cloudflare supports cron expressions with five fields, along with most Quartz scheduler ↗︎-like cron syntax extensions:

Field Values Characters
Minute 0-59 * , - /
Hours 0-23 * , - /
Days of Month 1-31 * , - / L W
Months 1-12, case-insensitive 3-letter abbreviations ("JAN", "aug", etc.) * , - /
Weekdays 1-7, case-insensitive 3-letter abbreviations ("MON", "fri", etc.) * , - / L #

Examples

Some common time intervals that may be useful for setting up your Cron Trigger:

  • * * * * *

    • At every minute
  • */30 * * * *

    • At every 30th minute
  • 45 * * * *

    • On the 45th minute of every hour
  • 0 17 * * sun or 0 17 * * 1

    • 17:00 (UTC) on Sunday
  • 10 7 * * mon-fri or 10 7 * * 2-6

    • 07:10 (UTC) on weekdays
  • 0 15 1 * *

    • 15:00 (UTC) on first day of the month
  • 0 18 * * 6L or 0 18 * * friL

    • 18:00 (UTC) on the last Friday of the month
  • 59 23 LW * *

    • 23:59 (UTC) on the last weekday of the month

Test Cron Triggers locally

Use cf dev, wrangler dev, or the Cloudflare Vite plugin to test Cron Triggers locally. You can use Local Explorer or send an HTTP request.

Cron Trigger testing in Local Explorer requires Wrangler 4.139.0 or later, or Cloudflare Vite plugin 1.60.0 or later. These requirements also apply to the development server started by cf dev.

Use Local Explorer

Local Explorer displays the exact Cron Triggers configured for the active environment. It can also test ad hoc expressions without changing your configuration.

To test a configured expression, define at least one Cron Trigger for the active environment. You can test an ad hoc expression without configuring one.

  1. Open Local Explorer and select the Worker you want to test.
  2. Select Cron Triggers > Configured Crons.
  3. Select Now or add a scheduled time preset.
  4. Select Trigger next to the expression you want to test.
  5. Review the handler outcome, noRetry() status, dispatched expression, and scheduled time.

Full invocation logs are available in the development session that owns the Worker. That session must have Observability turned on.

Each invocation is a one-off local test. Local development does not run Cron Triggers automatically.

To test an expression that is not configured, select Cron Triggers > Ad-Hoc Triggers. Ad hoc triggers stay in your browser and do not modify deployed Cron Triggers.

Use an HTTP request

Your local development server exposes two endpoints for scheduled invocations. The following examples use port 8787. Use the port printed by your development server, including when you start it with cf dev. Vite uses port 5173 by default.

Use the scheduled route

Send a request to /cdn-cgi/local/scheduled to invoke a scheduled handler.

curl "http://localhost:8787/cdn-cgi/local/scheduled"

By default, the endpoint returns the scheduled handler outcome as text. To return the structured scheduled handler result as JSON, pass ?format=json.

curl "http://localhost:8787/cdn-cgi/local/scheduled?format=json"
{
  "outcome": "ok",
  "noRetry": false
}

The noRetry field is true when the scheduled handler calls controller.noRetry().

To simulate different cron patterns, a cron query parameter can be passed in.

curl "http://localhost:8787/cdn-cgi/local/scheduled?cron=*+*+*+*+*"

Optionally, you can also pass a time query parameter to override controller.scheduledTime in your scheduled event listener.

curl "http://localhost:8787/cdn-cgi/local/scheduled?cron=*+*+*+*+*&time=1745856238000"

Use the Local Explorer API

To target an exact Worker available to Local Explorer, send a POST request to /cdn-cgi/local/explorer/api/local/scheduled?worker=<WORKER_NAME>. The worker query parameter must match the exact Worker name. To find available Worker names, send a GET request to /cdn-cgi/local/explorer/api/local/workers.

The JSON body requires a non-empty cron field. The optional scheduled_time field sets controller.scheduledTime using epoch milliseconds. If omitted, it defaults to the current time.

curl -X POST \
  "http://localhost:8787/cdn-cgi/local/explorer/api/local/scheduled?worker=my-worker" \
  -H "Content-Type: application/json" \
  --data '{"cron":"0 * * * *","scheduled_time":1745856238000}'

The response uses the Local Explorer API envelope. Its result includes the handler outcome and noRetry value. A successful API request does not necessarily mean the handler succeeded. Check result.outcome for the invocation result.

View past events

To view the execution history of Cron Triggers, view Cron Events:

  1. In the Cloudflare dashboard, go to the Workers & Pages page.

    Go to Workers & Pages ↗
  2. In Overview, select your Worker.

  3. Select Settings.

  4. Under Trigger Events, select View events.

Cron Events stores the 100 most recent invocations of the Cron scheduled event. Workers Logs also records invocation logs for the Cron Trigger with a longer retention period and a filter & query interface. If you are interested in an API to access Cron Events, use Cloudflare's GraphQL Analytics API.

Refer to Metrics and Analytics for more information.

Remove a Cron Trigger

Via the dashboard

To delete a Cron Trigger on a deployed Worker via the dashboard:

  1. In the Cloudflare dashboard, go to the Workers & Pages page.

    Go to Workers & Pages ↗
  2. Select your Worker.

  3. Go to Triggers > select the three dot icon next to the Cron Trigger you want to remove > Delete.

If a Worker is managed with Wrangler, Cron Triggers should be exclusively managed through the Wrangler configuration file.

When deploying a Worker with Wrangler any previous Cron Triggers are replaced with those specified in the triggers array.

  • If the crons property is an empty array then all the Cron Triggers are removed.
  • If the triggers or crons property are undefined then the currently deploy Cron Triggers are left in-place.
{
	"triggers": {
		// Remove all cron triggers:
		"crons": []
	}
}
[triggers]
crons = [ ]

Limits

Refer to Workers limits for the maximum number of Cron Triggers per account.

Green Compute

With Green Compute enabled, your Cron Triggers will only run on Cloudflare points of presence that are located in data centers that are powered purely by renewable energy. Organizations may claim that they are powered by 100 percent renewable energy if they have procured sufficient renewable energy to account for their overall energy use.

Renewable energy can be purchased in a number of ways, including through on-site generation (wind turbines, solar panels), directly from renewable energy producers through contractual agreements called Power Purchase Agreements (PPA), or in the form of Renewable Energy Credits (REC, IRECs, GoOs) from an energy credit market.

Green Compute can be configured at the account level:

  1. In the Cloudflare dashboard, go to the Workers & Pages page.

    Go to Workers & Pages ↗
  2. In the Account details section, find Compute Setting.

  3. Select Change.

  4. Select Green Compute.

  5. Select Confirm.

  • Triggers - Review Wrangler configuration file syntax for Cron Triggers.
  • Learn how to access Cron Triggers in ES modules syntax for an optimized experience.

Was this helpful?