A practical field guide from Automation Ace.
The short answer
To run recurring tasks on Cloudflare, add one or more cron expressions under triggers.crons in your Wrangler config and export a scheduled() handler from your Worker. Cloudflare runs the handler on that schedule, in UTC, with no server to keep alive. Use it for syncs, reports, cleanups, reminders, and health checks.
New to Workers? Start with Cloudflare Workers 101.
Step 1: add a Cron Trigger
// wrangler.jsonc
{
"name": "daily-report",
"main": "src/index.js",
"compatibility_date": "2026-09-01",
"triggers": {
"crons": ["0 13 * * 1-5", "*/15 * * * *"]
}
}
Each string is a standard five-field cron expression: minute, hour, day of month, month, day of week. Schedules run in UTC, so convert from your local time and remember daylight saving changes. See why automation dates are off by one day.
| Cron expression | Runs |
|---|---|
*/15 * * * * | Every 15 minutes |
0 * * * * | Every hour on the hour |
0 13 * * 1-5 | 13:00 UTC, Monday to Friday |
30 6 1 * * | 06:30 UTC on the 1st of each month |
0 0 * * 0 | Midnight UTC every Sunday |
Step 2: write the scheduled handler
// src/index.js
export default {
async scheduled(controller, env, ctx) {
switch (controller.cron) {
case '0 13 * * 1-5': // 13:00 UTC on weekdays
ctx.waitUntil(sendDailyReport(env));
break;
case '*/15 * * * *': // every 15 minutes
ctx.waitUntil(syncNewOrders(env));
break;
}
},
};
async function syncNewOrders(env) {
const cursor = (await env.STATE.get('orders_cursor')) || '1970-01-01T00:00:00Z';
const res = await fetch(`https://api.example.com/orders?updated_since=${encodeURIComponent(cursor)}`, {
headers: { Authorization: `Bearer ${env.SHOP_API_KEY}` },
});
if (!res.ok) throw new Error(`Orders API ${res.status}`);
const { orders, next_cursor } = await res.json();
for (const order of orders) {
// ...create or update records elsewhere...
}
if (next_cursor) await env.STATE.put('orders_cursor', next_cursor); // advance only after success
}
async function sendDailyReport(env) { /* build and send a summary */ }
controller.cron tells you which schedule fired, so one Worker can run several jobs. The sync example keeps a cursor in KV so each run fetches only new records, and advances it only after success. That is the same pattern as API polling and sync cursors in Zapier Storage.
Step 3: test before deploying
npx wrangler dev --test-scheduled
# then, in another terminal:
curl "http://localhost:8787/__scheduled?cron=*/15+*+*+*+*"
Then deploy with npx wrangler deploy. Cloudflare's dashboard shows past cron executions, and npx wrangler tail streams logs.
Scheduled automation ideas
- Daily or weekly reports emailed or posted to Slack.
- Incremental syncs between apps using a cursor.
- Reminders for overdue invoices or tasks. See invoice reminders.
- Cleanup jobs: archive old records, delete expired files.
- Uptime and data checks: ping endpoints or verify yesterday's data arrived.
- AI digests: summarize the day's tickets or mentions with Workers AI.
Limits and reliability tips
- Trigger count: the free plan allows a small number of Cron Triggers per account (five at the time of writing); paid plans allow many more. Combine jobs in one Worker and branch on
controller.cron. - CPU time: scheduled runs share Worker CPU limits. For long jobs, have the cron start a Workflow or push items to a Queue.
- Overlaps: a slow run can overlap the next; design jobs to be idempotent.
- Missed-run awareness: record the last successful run time in KV and alert if it gets stale.
- Business hours: restrict schedules with day-of-week fields. Compare business-hours Zaps.
Cron Triggers are a flexible alternative to Zapier's Schedule trigger; see custom Zap schedules for the no-code approach.
Frequently asked questions
How do I schedule a Cloudflare Worker?
Add cron expressions under triggers.crons in your Wrangler config and export a scheduled(controller, env, ctx) handler. Cloudflare runs the handler on each schedule.
What time zone do Cloudflare Cron Triggers use?
UTC. Convert your local schedule to UTC and account for daylight saving time changes.
How many Cron Triggers can I use on the free plan?
Cloudflare's documentation lists five Cron Triggers per account on the Workers Free plan at the time of writing, with more on paid plans. Combine jobs in one Worker and branch on controller.cron to save triggers.
How do I test a Cloudflare Cron Trigger locally?
Run npx wrangler dev --test-scheduled, then request /__scheduled with a cron query parameter to invoke the scheduled handler.
How do I run long scheduled jobs?
Keep the scheduled handler short and have it start a Cloudflare Workflow or send items to a Queue, which handle long-running, retryable work.
Disclaimer: Zapier features, plan availability, and settings can change. Confirm current details in Zapier's help documentation and Cloudflare's developer documentation and pricing pages. Limits and plan features change over time. Code samples are simplified starting points; add your own validation, error handling, and security review before production use before relying on a specific setting. This article may include links to apps, products, or services; some links may be affiliate links, which means Automation Ace may earn a commission at no extra cost to you.