---
description: Running a container on a schedule using Cron Triggers
title: Cron Container
image: https://developers.cloudflare.com/og-docs.png
---

[Skip to content](#main-content)

> 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.

# Cron Container

Running a container on a schedule using Cron Triggers

Last updated Aug 28, 2026|Copy as Markdown|[View as Markdown](https://codex-container-api-docs.previews.developers.cloudflare.com/containers/examples/cron/index.md)|[Agent setup](https://codex-container-api-docs.previews.developers.cloudflare.com/agent-setup/)

To launch a container on a schedule, you can use a Workers [Cron Trigger](https://codex-container-api-docs.previews.developers.cloudflare.com/workers/configuration/cron-triggers/).

For a full example, see the [Cron Container Template ↗](https://github.com/mikenomitch/cron-container/tree/main).

Use a cron expression in your Wrangler config to specify the schedule:

```jsonc
{
	"name": "cron-container",
	"main": "src/index.ts",
	"triggers": {
		"crons": [
			"*/2 * * * *" // Run every 2 minutes
		]
	},
	"containers": [
		{
			"class_name": "CronContainer",
			"image": "./Dockerfile"
		}
	],
	"durable_objects": {
		"bindings": [
			{
				"class_name": "CronContainer",
				"name": "CRON_CONTAINER"
			}
		]
	},
	"migrations": [
		{
			"new_sqlite_classes": ["CronContainer"],
			"tag": "v1"
		}
	]
}
```

```toml
name = "cron-container"
main = "src/index.ts"

[triggers]
crons = [ "*/2 * * * *" ]

[[containers]]
class_name = "CronContainer"
image = "./Dockerfile"

[[durable_objects.bindings]]
class_name = "CronContainer"
name = "CRON_CONTAINER"

[[migrations]]
new_sqlite_classes = [ "CronContainer" ]
tag = "v1"
```

Then call the Container from the `scheduled()` handler in the Worker. The raw API example expects the Container to expose a `POST /run` endpoint that starts the scheduled task.

```js
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;
		await container.setInactivityTimeout(10_000);

		if (!container.running) {
			container.start();
		}

		const port = container.getTcpPort(8080);
		let lastError;
		for (let attempt = 0; attempt < 50; attempt++) {
			try {
				await port.fetch("http://container/");
				lastError = undefined;
				break;
			} catch (error) {
				lastError = error;
				await scheduler.wait(100);
			}
		}
		if (lastError) {
			throw lastError;
		}

		const response = await port.fetch("http://container/run", {
			method: "POST",
			body: JSON.stringify({ startTime }),
			headers: { "content-type": "application/json" },
		});
		if (!response.ok) {
			throw new Error(`Container returned ${response.status}`);
		}
	}
}

export default {
	async fetch() {
		return new Response("This Worker runs a scheduled Container task.");
	},

	async scheduled(_controller, env) {
		await env.CRON_CONTAINER.getByName("cron").run(new Date().toISOString());
	},
};
```

```ts
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!;
		await container.setInactivityTimeout(10_000);

		if (!container.running) {
			container.start();
		}

		const port = container.getTcpPort(8080);
		let lastError: unknown;
		for (let attempt = 0; attempt < 50; attempt++) {
			try {
				await port.fetch("http://container/");
				lastError = undefined;
				break;
			} catch (error) {
				lastError = error;
				await scheduler.wait(100);
			}
		}
		if (lastError) {
			throw lastError;
		}

		const response = await port.fetch("http://container/run", {
			method: "POST",
			body: JSON.stringify({ startTime }),
			headers: { "content-type": "application/json" },
		});
		if (!response.ok) {
			throw new Error(`Container returned ${response.status}`);
		}
	}
}

export default {
	async fetch(): Promise<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().toISOString());
	},
};
```

```ts
import { Container, getContainer } from "@cloudflare/containers";

export class CronContainer extends Container {
  sleepAfter = '10s';

  override onStart() {
    console.log('Starting container');
  }

  override onStop() {
    console.log('Container stopped');
  }
}

export default {
	async fetch(): Promise<Response> {
		return new Response("This Worker runs a cron job to execute a container on a schedule.");
	},

	async scheduled(_controller: ScheduledController, env: { CRON_CONTAINER: DurableObjectNamespace<CronContainer> }) {
		const container = getContainer(env.CRON_CONTAINER);
		await container.start({
			envVars: {
				MESSAGE: "Start Time: " + new Date().toISOString(),
			},
		});
	},
};
```

Was this helpful?

YesNo

## On this page

[![](https://codex-container-api-docs.previews.developers.cloudflare.com/_astro/logo.te5VL_aD.svg)Docs](https://codex-container-api-docs.previews.developers.cloudflare.com/)

```json
{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/containers/examples/cron/#page","headline":"Cron Container · Cloudflare Containers docs","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/og-docs.png","dateModified":"2026-08-28","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/"}}
```
