Migrate from Cloudflare Workers

Workers is V8-isolate edge compute; ours is V8-isolate plus Python, Rust, Bun, Deno, and full WASI. The handler signature is the same — Request in, Response out — so the migration is mostly config, not code.

The handler diff

// Workers (export default form)
- export default {
-   async fetch(request, env, ctx) {
-     return new Response("hi");
-   },
- };

// Joule Cloud Functions
+ export default async function (req) {
+   return new Response("hi");
+ }

Deploy

# Workers
- wrangler deploy

# Joule Cloud
+ invisible fn deploy worker.js \
+   --route /api \
+   --runtime node-22

Service map

CloudflareJoule Cloud
WorkersFunctions
R2Object Store
D1 / HyperdriveJouleDB
KVJouleDB (small + indexed) or Object Store
Durable ObjectsStateful Functions w/ region-pinned db row — pattern, not primitive
Workers AIInference
QueuesFunctions + queue trigger
PagesStatic via Object Store + edge cache, or Functions for SSR

R2 → Object Store

R2 already exposes the S3 API surface, so client-side it's just swapping the endpoint. See Migrate from AWS S3 for SDK config (Boto3, AWS SDK v3, etc.).

Bindings → env vars

Workers wires resources (KV, R2, Queues) into env via bindings declared in wrangler.toml. Joule Cloud injects them as standard environment variables declared in invisible.hcl:

workload "api" {
  image = "..."
  env = {
    DATABASE_URL = database.main.url
    OBJECT_BUCKET = bucket.uploads.url
  }
}

Cron triggers

- # wrangler.toml
- [triggers]
- crons = ["0 * * * *"]

+ # Joule Cloud
+ invisible fn deploy job.js --cron "0 * * * *"

What you keep

What you gain