A new application release does not always have to mean stopping every node and starting its process again. Deno’s open-source project celld offers one model for applications built with Cloudflare Workers APIs: publish a deployment manifest to object storage, then let running nodes adopt the new version in place.
The names matter. celld is a Deno project for self-hosting, not a Cloudflare product. It is not an official Cloudflare portability guarantee, either. Its goal is to run a defined set of Workers-style runtime and services on machines you operate. The celld project and documentation list Workers, Durable Objects, KV, Queues, D1, R2, Workflows, Cron Triggers and static assets within stated boundaries.
What does deploying without a restart mean?
In celld, one process on one machine is a node. Nodes that use the same bucket form a fleet. An application is deployed as a bundle and manifest to supported object storage, such as S3-compatible storage, Google Cloud Storage or Azure Blob Storage.
After a new version is deployed, each node checks deploy/current.json at a configured interval, 30 seconds by default in the documentation, and adopts the new deployment without restarting its process. A request that began on the old code continues on that version. An active Durable Object moves to the new version when it has no work in progress, or when the configured maximum age forces a move. The deployment and version-transition behavior
“Without a restart” therefore means the node process does not have to be restarted to receive an application deployment. It does not mean every request switches versions at once or that two versions never run together. During rollout, a Worker on one version may call a Durable Object on another. Code and messages should remain compatible with the previous version during that transition.
If a cell stays active beyond CELLD_DEPLOY_MAX_AGE_S (60 seconds by default in the documentation), celld can force the move, cancel the running work and close regular WebSockets with code 1012. Hibernatable WebSockets follow a different path. Teams should test long-running requests and reconnect behavior instead of checking only whether the node process stays up.
This model may suit teams that release often and do not want every application deployment tied to a fleet restart. Upgrading the celld runtime itself is a separate operation, with version-specific requirements. Changing the runtime binary is not the same as deploying an application bundle.
Bindings pass runtime resources to the app, but they are not a DI container
Cloudflare Workers exposes configured resources through env, including D1 databases, queues and object storage. Cloudflare calls these bindings: a way for a Worker to access resources and APIs provided by the runtime. Cloudflare Workers bindings
From an application-design perspective, the runtime supplies dependencies. But bindings are not a full dependency-injection container. They do not assemble an application object graph or resolve arbitrary dependencies. Developers still decide how services use the provided resources.
An Order API could keep business logic separate from runtime SDKs by defining its own interfaces:
interface OrderStore {
save(order: Order): Promise<void>;
}
interface ReviewJobs {
publish(orderId: string): Promise<void>;
}
function createOrderService(deps: {
orders: OrderStore;
reviewJobs: ReviewJobs;
}) {
return {
async submit(order: Order) {
await deps.orders.save(order);
await deps.reviewJobs.publish(order.id);
},
};
}
A Worker handler can construct D1OrderStore(env.ORDERS_DB) and QueueReviewJobs(env.REVIEW_JOBS), then pass them to createOrderService(). A unit test can pass fake stores and queues instead. The separation is specific: the business service knows its own work interfaces, not whether persistence uses D1 or which SDK sends the message. The adapters and binding configuration still need separate implementation and tests.
Moving to another runtime requires adapters for its resources and tests for each service’s actual behavior, such as transactions, retries, ordering, timeouts and errors. A binding with the same name does not guarantee identical semantics.
These boundaries can make team ownership clearer: application engineers own business rules and interfaces, platform engineers own adapters and runtime configuration, and infrastructure engineers own nodes, networking and storage. An adapter change then has a clear place to test, and adding another runtime does not require rewriting every business rule. That benefit comes from the team’s design, not from celld itself.
