Cron container
Running a container on a schedule using Cron Triggers
Last updated Oct 12, 2026 Run a short container task every two minutes with a Workers Cron Trigger. The task prints its scheduled time, then exits.
Configure the schedule
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "cron-container",
"main": "src/index.ts",
"upload_source_maps": true,
// Set this to today's date
"compatibility_date": "2026-10-27",
"observability": {
"enabled": true
},
"triggers": {
"crons": [
"*/2 * * * *"
]
},
"containers": [
{
"class_name": "CronContainer",
"scheduling_policy": "durable_object",
"images": {
"base": {
"dockerfile": "./Dockerfile"
}
}
}
],
"durable_objects": {
"bindings": [
{
"name": "CRON_CONTAINER",
"class_name": "CronContainer"
}
]
},
"exports": {
"CronContainer": {
"type": "durable-object",
"storage": "sqlite"
}
}
}
name = "cron-container"
main = "src/index.ts"
upload_source_maps = true
# Set this to today's date
compatibility_date = "2026-10-27"
[observability]
enabled = true
[triggers]
crons = ["*/2 * * * *"]
[[containers]]
class_name = "CronContainer"
scheduling_policy = "durable_object"
[containers.images.base]
dockerfile = "./Dockerfile"
[[durable_objects.bindings]]
name = "CRON_CONTAINER"
class_name = "CronContainer"
[exports.CronContainer]
type = "durable-object"
storage = "sqlite"
Start and await the task
src/index.jsjs
import { DurableObject } from "cloudflare:workers";
export class CronContainer extends DurableObject {
currentRun;
run(startTime) {
this.currentRun ??= this.runOnce(startTime).finally(() => {
this.currentRun = undefined;
});
return this.currentRun;
}
async runOnce(startTime) {
const container = this.ctx.container;
if (!container.running) {
container.start({
image: container.images.base,
instance: "lite",
enableInternet: false,
env: { MESSAGE: `Scheduled time: ${startTime}` },
});
}
await container.monitor();
}
}
export default {
fetch() {
return new Response("This Worker runs a scheduled Container task.");
},
async scheduled(controller, env) {
await env.CRON_CONTAINER.getByName("cron").run(
new Date(controller.scheduledTime).toISOString(),
);
},
};
src/index.tsts
import { DurableObject } from "cloudflare:workers";
interface Env {
CRON_CONTAINER: DurableObjectNamespace<CronContainer>;
}
export class CronContainer extends DurableObject<Env> {
private currentRun: Promise<void> | undefined;
run(startTime: string): Promise<void> {
this.currentRun ??= this.runOnce(startTime).finally(() => {
this.currentRun = undefined;
});
return this.currentRun;
}
private async runOnce(startTime: string): Promise<void> {
const container = this.ctx.container!;
if (!container.running) {
container.start({
image: container.images.base,
instance: "lite",
enableInternet: false,
env: { MESSAGE: `Scheduled time: ${startTime}` },
});
}
await container.monitor();
}
}
export default {
fetch(): Response {
return new Response("This Worker runs a scheduled Container task.");
},
async scheduled(controller: ScheduledController, env: Env): Promise<void> {
await env.CRON_CONTAINER.getByName("cron").run(
new Date(controller.scheduledTime).toISOString(),
);
},
} satisfies ExportedHandler<Env>;
All triggers use the same Durable Object. If a run is still active, another trigger waits for that run instead of starting a second task. This example does not queue overlapping runs or guarantee exactly-once execution. Make tasks idempotent when they modify external data.
monitor() reports completion or failure, not HTTP readiness. Keep this task short enough to finish within the Cron Trigger execution limits.
Define the task
Dockerfiledockerfile
FROM alpine:3.20
CMD ["sh", "-c", "printf '%s\\n' \"$MESSAGE\""]
Test the schedule locally
Start a Docker-compatible engine and use Wrangler 4.136.0 or later.
npmyarnpnpmbun
npm i -D wrangler
yarn add -D wrangler
pnpm add -D wrangler
bun add -d wrangler
npmyarnpnpm
npx wrangler dev --test-scheduled
yarn wrangler dev --test-scheduled
pnpm wrangler dev --test-scheduled
In another terminal, trigger the scheduled handler:
curl 'http://localhost:8787/__scheduled?cron=*/2+*+*+*+*'
Check the container logs for the scheduled time. After deployment, Cron Triggers invoke the handler automatically.
Was this helpful?
YesNo
On this page
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/containers/examples/cron/#page","headline":"Cron container","description":"Running a container on a schedule using Cron Triggers","url":"https://developers.cloudflare.com/containers/examples/cron/","inLanguage":"en","image":"https://developers.cloudflare.com/containers/examples/cron/og.png?v=8aa941b4f4fd1c08","dateModified":"2026-10-12","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}
description: Various examples calling Containers directly from Durable Objects title: More examples image: https://developers.cloudflare.com/containers/examples/durable-object-interface/og.png?v=2fb49aba202d1f04
Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/containers/llms.txt
Use this file to discover all available pages before exploring further.
Docs