How images and running Container instances update depends on the scheduling policy for the application.
With the durable_object policy, Wrangler prepares the named images for the application. Durable Object code can access their immutable references and selects an image and instance size when it calls ctx.container.start(). When an image reference changes, the Durable Object code decides whether to stop the running Container and start it with the new image or let it continue with the previous image. This application-controlled restart is how you roll out image changes with the durable_object policy. These instances do not participate in application-wide image rollouts.
With the default policy, Wrangler uploads or resolves the application image. Cloudflare distributes that image across its network and prepares capacity for new instances. Changes to the image or instance type use a rollout.
Worker code goes live on deploy before any application-wide Container rollout finishes. Refer to Deploy Containers.
flowchart LR
accTitle: Container instance lifecycle
accDescr: A Worker accesses a container through its Durable Object. The container moves from stopped to starting, running but not ready, ready for traffic, stopping, and stopped.
Worker["Worker"] -->|Durable Object binding| DurableObject["Durable Object"]
DurableObject -->|<code>ctx.container</code>| Container
subgraph Container["Container instance"]
direction TD
Stopped["Stopped"]
Starting["Starting<br/><code>start()</code> called"]
Running["Running<br/>Not ready"]
Ready["Ready<br/>Accepting traffic"]
Stopping["Stopping<br/>Stop requested"]
StoppedAgain["Stopped"]
Stopped --> Starting --> Running --> Ready --> Stopping --> StoppedAgain
end
A Container can only be accessed through its Durable Object. A Worker sends a request to the Durable Object, which accesses the Container through ctx.container.
An inactivity timeout, signal(), destroy(), a rollout, or a process exit can stop the instance. If startup fails or the process exits early, the instance returns to the stopped state.
The ctx.container.running property becomes true before the process is ready to accept traffic. Check port readiness before you send the first request.
For new applications, manage this lifecycle through the Durable Object Container API. It lets the Durable Object coordinate container compute with persistent state and alarms. Existing applications may use the Container class. To compare both APIs, refer to Containers APIs.
Recall that Containers are backed by Durable Objects and Workers. Requests are first routed through a Worker, which is generally handled by a datacenter in a location with the best latency between itself and the requesting user. A different datacenter may be selected to optimize overall latency, if Smart Placement is on, or if the nearest location is under heavy load.
Because all Container requests are passed through a Worker, end-users cannot make non-HTTP TCP or UDP requests to a Container instance. If you have a use case that requires inbound TCP or UDP from an end-user, please let us know ↗︎.
From the Worker, a request passes through a Durable Object instance. You can extend DurableObject and use ctx.container directly, or extend the Container class.
Each Durable Object instance is a globally routable isolate that can execute code and store state. This allows
developers to address and route to specific container instances, run code when a container exits, and store persistent state associated with each instance.
When a Durable Object requests a new Container instance, Cloudflare selects eligible capacity with the required image available. The durable_object policy uses the image and instance options supplied to ctx.container.start(). The default policy uses the application image and instance type from Wrangler configuration.
Starting additional Container instances can use other locations where the image is available. Cloudflare prepares additional capacity as demand grows. Because prepared capacity is finite, some Container instances may start in locations farther from the end user. You are only charged for actively running instances, not for prepared images that are not running.
A cold start is when a container instance is started from a completely stopped state.
If you call env.MY_CONTAINER.get(id) with a completely novel ID and launch
this instance for the first time, it will result in a cold start.
This will start the container image from its entrypoint for the first time. Depending
on what this entrypoint does, it will take a variable amount of time to start.
Container cold starts can often be in the 1-3 second range, but this is dependent on image size and code execution time, among other factors.
When a request starts a new container instance, the nearest location with a pre-fetched image is selected. Subsequent requests to a particular instance, regardless of where they originate, will be routed to this location as long as the instance stays alive.
However, once that container instance stops and restarts, future requests could be routed to a different location. This location will again be the nearest location to the originating request with a pre-fetched image.
Each container instance runs in a Firecracker microVM with its own kernel and network. No other workload on the Cloudflare network shares that kernel. Your image runs as a Linux container inside the VM.
Containers should be built for the linux/amd64 architecture, and should stay within
size limits.
Logging, metrics collection, and networking are automatically set up on each container, as configured by the developer.
With the Durable Object Container API, call setInactivityTimeout() to let the runtime stop the container after the Durable Object becomes inactive. The Durable Object becomes inactive when it stops receiving requests. The timeout can keep the container available while the Durable Object sleeps. You can also stop a container with signal() or destroy().
The Container class sets sleepAfter to 10 minutes by default. Its onActivityExpired() implementation calls stop(). You can change the duration or override the hook.
When the platform is about to stop a container instance, it:
- Sends
SIGTERMto the main process in the container. - Waits up to 15 minutes for that process to exit.
- Sends
SIGKILLif the process is still running.
Handle SIGTERM in your image if you need cleanup before exit. The same sequence runs when a rollout replaces a container instance with a new image.
The Durable Object Container API provides monitor(). Its promise resolves when the container exits and rejects when the container errors.
The Container class adds hooks that run Worker code when the container changes state:
onStart()— Runs after the container has started.onStop()— Runs after the container process exits. Receives the exit code and reason for the stop.onActivityExpired()— Runs when thesleepAftertimer expires with no incoming requests. The default implementation callsstop()to shut down the container. You can use this to only stop the container on certain conditions.onError()— Runs when container startup or port checking fails.
Refer to the status hooks example for a full implementation.
All disk is ephemeral by default. When a Container instance goes to sleep, the next time it starts, it uses a fresh disk from the container image.
If you need point-in-time filesystem state, Container applications that use the durable_object scheduling policy can create and restore a snapshot.
Snapshots are immutable, so later file changes require a new snapshot. For more
information, refer to Snapshots.
You can also use FUSE to persist disk to R2 or other object storage backends. Though you should not expect native SSD-like performance while using FUSE.
- A developer deploys a Container. Cloudflare automatically readies instances across its Network.
- A request is made from a client in Bariloche, Argentina. It reaches the Worker in a nearby Cloudflare location in Neuquen, Argentina.
- This Worker request calls
getContainer(env.MY_CONTAINER, "session-1337"). Under the hood, this brings up a Durable Object, which then callsthis.ctx.container.start. - This requests the nearest free Container instance. Cloudflare recognizes that an instance is free in Buenos Aires, Argentina, and starts it there.
- A different user needs to route to the same container. This user's request reaches the Worker running in Cloudflare's location in San Diego, US.
- The Worker again calls
getContainer(env.MY_CONTAINER, "session-1337"). - If the initial container instance is still running, the request is routed to the original location in Buenos Aires. If the initial container has gone to sleep, Cloudflare will once again try to find the nearest "free" instance of the Container, likely one in North America, and start an instance there.