env and ctx objects, imports, web API differences, crypto support, limits, and compatibility flags. For a summary of the differences from Cloudflare, see Differences from Cloudflare Workers.
Entry module
The entry module is the file thatmain names in the wrangler.json file, for example index.js. It’s a module Worker: it exports a default object with handlers, and it exports each class that the wrangler.json file names.
index.js
wrangler.json file names, such as a Durable Object class or a Workflow class. If the entry module exports any other value, such as export const x = 1, then the App doesn’t start.
Handlers
The default export can define the following handlers.
celld has no
tail or email handler.
The entry module also exports the classes that celld runs. The following table lists the base classes, which you import from the cloudflare:workers module.
The env object
The env object holds the bindings that you declare in the wrangler.json file, the vars values, and the Secrets. Each binding name is a property: a D1 binding named DB is env.DB. If a Secret and a var have the same name, then the Secret replaces the var.
Pass env to your functions as a parameter. Don’t store it in a module-level variable.
For more information, see Vars and Secrets.
The ctx object
The ctx object is the third argument of each handler. The following table lists its members.
In a Durable Object,
this.ctx.exports gives the same stubs. A Durable Object doesn’t need ctx.waitUntil, because pending I/O stays alive after the handler returns.
The public origin
In production,request.url has the App’s public origin, such as https://<slug>.judt.dev. On the dev server, request.url names the sandbox over http.
Judt sends the X-Forwarded-Host and X-Forwarded-Proto headers with the public origin on each request, in preview and in production. Judt replaces any value that the client sent. Use these headers when you build an absolute URL, such as an OAuth redirect, a feed link, or a webhook signature, or when you compare the Origin header:
Imports
The entry module can import relative modules, such as./src/db.js, the cloudflare:* modules in the following table, and the Node.js built-in modules that celld supports. At deploy, esbuild bundles the entry module, its relative imports, and the npm packages that it imports. For more information, see npm packages and builds.
The following table lists the cloudflare:* modules that work.
Node.js built-in modules
The following Node.js built-in modules work without thenodejs_compat flag. Node.js built-ins are always on.
Other modules
All othernode:* and cloudflare:* modules import without an error, but they throw an error on the first call. An npm package that depends on one of these modules fails when it calls the module. Use web APIs instead.
Web API differences
celld supports the standard web APIs of Workers. The following table lists each API group and how it behaves on celld.Crypto
Thecrypto.subtle interface supports the following algorithms:
- SHA digests
- HMAC
- HKDF
- PBKDF2
- AES-GCM
- RSASSA-PKCS1-v1_5
- RSA-PSS
- RSA-OAEP
- ECDSA
- Ed25519
- X25519
HS256, RS256, PS256, ES256, or EdDSA work.
Crypto limits
The crypto implementation has the following limits:- ECDSA supports only the P-256 curve with SHA-256, so
ES384andES512don’t work. - AES-GCM tags must be 96 to 128 bits long.
- You can’t export or wrap a secret key in
jwkformat. - The
node:cryptomodule has no ciphers, no Diffie-Hellman, no RSA-PSS, no DSA, and no streaming signatures. Usecrypto.subtlefor these operations.
Hash passwords
To hash a password, use PBKDF2 with SHA-256, a random 16-byte salt, and at least 100,000 iterations. Store the salt and the iteration count with the hash.Compare secrets in constant time
To compare a secret, such as a token or a webhook signature, use a comparison that takes the same time for every input. The following function signs both values with a random HMAC key and compares the results:safeEqual.
Limits
The following table lists the runtime limits.
Don’t read large bodies into memory. Stream them instead. Each binding has its own limits. For more information, see the page for that binding.
Outbound calls
Keep the API keys for outbound calls in Secrets, and read them fromenv, for example env.ANTHROPIC_API_KEY. For more information, see Vars and Secrets.
Set a timeout
Set a timeout on each outbound call:Compatibility flags
Keep thecompatibility_date value of your App. celld obeys only the following compatibility flags and their off flags:
assets_navigation_prefers_asset_servingdelete_all_deletes_alarmfetcher_no_get_put_deletejs_rpcqueue_json_messagessqlite_vecwebsocket_standard_binary_type
compatibility_flags list without effect. For the effect of each flag, its off flag, and the date from which it’s on by default, see Compatibility settings. You don’t need the nodejs_compat flag, because Node.js built-in modules are always on.
Patterns
Route requests without a dependency
You can route requests withURLPattern and no framework. The following entry module matches each request against a list of routes, and catches errors at the top level:
index.js
getLink and createLink functions are your route handlers. Each one receives the request, env, ctx, and the named groups from the path.
Handle input and errors
We recommend the following practices for each route:- Validate all input. Check the type, the length, and the format of each value.
- Catch errors at the top level, and write them with
console.error. Logs fromconsole.*and uncaught exceptions go to the App logs. - Escape user text before you put it into HTML.