Skip to main content
A Judt App is one Worker in the style of Cloudflare Workers. It runs on celld, the Judt runtime. Most of what you know about Workers applies to Judt Apps. This page summarizes where celld differs, so that you can find the changes that matter before you port code or reach for a familiar feature. Each item links to the page that covers it in full. If this documentation and the Cloudflare documentation disagree, follow this documentation.

What celld is

celld is a separate runtime. It embeds V8 and implements the Workers runtime API. It isn’t workerd, Node.js, or a browser. celld runs your App in the sandbox as a dev server, and in production after a deploy. Write standard web-platform JavaScript: fetch, Request, Response, streams, URL, and Web Crypto. Use the bindings that you declare in the wrangler.json file. A subset of Node.js built-in modules works without the nodejs_compat flag. For more information, see Runtime reference.

Unsupported products and features

celld doesn’t provide Vectorize, Hyperdrive, Browser Rendering, or Email Workers, so the entry module can’t export an email handler. The following table lists the other unsupported features and what to do instead.

Behavior differences

The following differences are the ones that most often surprise developers who know Workers.

The Cache API always misses

caches.default and caches.open exist, but every lookup misses and put stores nothing. The cache option of fetch isn’t available. To cache a value, store it in KV with an expirationTtl. For more information, see Web API differences.

KV is strongly consistent

On celld, one owner serves each KV namespace, so a get always returns the last put from every node. Cloudflare guidance about stale reads doesn’t apply. There’s no edge cache, and the cacheTtl option has no effect. KV still has no atomic increment and no compare-and-swap, so use a Durable Object or D1 for counters. For more information, see KV.

R2 has no presigned URLs, public buckets, or S3 API

Every upload and download goes through your Worker, which handles authorization and streams the body. To share a file, create a random token, store the token-to-key mapping in KV with an expiry, and serve the file from a Worker route. R2 event notifications, ssecKey, lifecycle rules, and jurisdiction aren’t available. For more information, see R2.

D1 has no read replicas, Time Travel, or SQL transactions

Every D1 query goes to the primary database, so each read sees all committed writes. The withSession() method always uses the primary. The dump() method throws, and there’s no Time Travel and no REST API. Application SQL can’t use BEGIN, COMMIT, ROLLBACK, or SAVEPOINT. To run statements in one transaction, use batch(). Judt applies migrations at deploy, and the dev server applies them to the dev database. For more information, see D1.

The request.cf object has no location data

The request.cf object has no geolocation and no colo data. celld also removes the Content-Length header from Worker responses, except for responses to HEAD requests. For more information, see Web API differences.

Clocks advance only at I/O

Date.now() and performance.now() move forward only when your code does I/O. A loop that only uses the CPU measures 0 ms. For more information, see Web API differences.

The wrangler.json file accepts few keys

The wrangler.json file accepts only name, main, no_bundle, compatibility_date, compatibility_flags, vars, and the binding keys that the feature pages document. Deploy refuses every other key, for example routes, env, observability, ai, and build. To run a build, add a build script to the package.json file. For more information, see Configure wrangler.json.

celld creates bindings on first use

You don’t provision D1 databases, KV namespaces, R2 buckets, or queues. celld creates each one the first time that your code uses it. A typo in database_name, a KV id, or bucket_name therefore gives you a new, empty store, and the old data stays under the old name. For more information, see Configure wrangler.json.
Don’t change the App name, a Durable Object class name, a D1 database_name or database_id, a KV id, or a bucket_name after data exists. The new name points to new, empty storage, and your code can no longer reach the old data.

Most compatibility flags have no effect

celld obeys a short list of compatibility flags and accepts all other flags without effect. Node.js built-in modules are always on. For more information, see Compatibility flags.

Other differences by product

The following table lists the remaining differences for each product. The linked page covers each one.