Cloudflare Workers
Rule
Rules for Cloudflare Workers, KV, R2, and related services. See typescript.md for general type rules and security.md for input validation.
Runtime
- MUSTUse ES module format (
export default { fetch }). Never use Service Worker format. - MUSTType all bindings in an
Envinterface. Never use untypedenv. - MUSTUse
crypto.randomUUID()— not theuuidpackage (crashes in Workers runtime). - MUSTUse Web APIs (
fetch,Request,Response,crypto,TextEncoder) — not Node.js equivalents. - NEVERImport
fs,path,net,child_process, or other Node.js-only modules. - SHOULDEnable Node.js compatibility (
nodejs_compat) only when a dependency requires it.
Limits
| Resource | Free | Paid |
|---|---|---|
| CPU time per request | 10ms | 5 min |
| Memory per isolate | 128 MB | 128 MB |
| Subrequests per request | 50 | 1,000 |
| Environment variables | 64 (5 KB each) | 128 (5 KB each) |
| Request body | 100 MB | 100 MB+ |
- MUSTDesign for 128 MB memory — no large in-memory buffers. Stream large responses.
- SHOULDKeep CPU time well under limits. Most requests should be <2ms.
Wrangler & Deployment
- MUSTUse
wrangler secret putfor secrets. Never put secrets inwrangler.toml. - MUSTSet explicit
bucket_name,database_name,namespace_idin bindings — don't rely on binding name alone. - MUSTSet
compatibility_dateto a recent date. Update quarterly. - SHOULDUse
wrangler devfor local development with real bindings. - SHOULDUse
wrangler deployfor production (not manual uploads).
KV
- MUSTDesign for eventual consistency — writes propagate globally in ~60 seconds.
- MUSTRespect 1 write per second per key limit. Exceeding returns 429.
- MUSTValidate sizes before write: keys ≤512 bytes, values ≤25 MB, metadata ≤1 KB.
- MUSTCheck
list_completeflag when paginating — never assume result count equals completion. - SHOULDUse bulk reads (up to 100 keys) instead of individual reads.
- SHOULDSet
cacheTtl(minimum 60s) for frequently read keys to reduce latency. - NEVERUse KV for atomic operations or strong consistency. Use Durable Objects instead.
R2
- MUSTUse multipart uploads for objects >100 MB. Uncompleted uploads auto-abort after 7 days.
- MUSTCheck
truncatedproperty when listing — max 1,000 results per call. - MUSTUse prefix filtering when listing. Unfiltered listing is expensive at scale.
- SHOULDLeverage strong consistency — R2 writes are immediately visible globally after Promise resolves.
- SHOULDUse conditional operations (
onlyIf) to avoid unnecessary reads/writes.
Error Handling
- MUSTWrap the top-level
fetchhandler in try/catch. Unhandled errors crash the isolate. - MUSTReturn structured error responses — not raw exception messages.
- SHOULDLog errors with
console.errorfor wrangler tail / Logpush visibility. - NEVERExpose internal error details, binding names, or KV namespace IDs to clients.
Testing
- MUSTUse Vitest with
@cloudflare/vitest-pool-workersfor unit tests against real Workers runtime. - SHOULDTest with real bindings in
wrangler devfor integration tests. - SHOULDUse
miniflarefor isolated local testing when real bindings aren't needed. - NEVERMock the Workers runtime in tests — the runtime has real behavioral differences from Node.js.
Security
- MUSTValidate all input at the worker boundary (headers, query params, body).
- MUSTAuthenticate requests before accessing bindings.
- MUSTUse
crypto.subtlefor cryptographic operations (AES, HMAC, SHA). - NEVERTrust
cf-connecting-ipor other headers without Cloudflare in front. - NEVERStore unencrypted secrets in KV or R2.