HelloWorld on Our First Platform: Cloudflare


The first milestone in a portability story is never glamorous. It’s the moment you can take one tiny program, run it in your own tooling, and also package it for a real platform without rewriting it.

For Distlang, that moment is a Worker-style “Hello World” running end-to-end, with Cloudflare as our first target. Cloudflare Workers is a natural starting point because it has a clear runtime model and a well-defined deployment toolchain.

If you want to follow along with the exact code in this post, the example lives here:

https://github.com/distlanglabs/distlang/tree/main/examples/helloworld

The smallest Worker that matters

Here is the whole example:

examples/helloworld/index.js

https://github.com/distlanglabs/distlang/blob/main/examples/helloworld/index.js

export default {
  async fetch(request, env, ctx) {
    console.log("Hello worker fetch will return a Response object");
    return new Response("Hello Worker!");
  },
};

This matches the Worker module shape Cloudflare expects: your module exports a default object with an async fetch() handler. When a request arrives, the platform calls fetch(request, env, ctx) and expects a Response back.

Running locally: what Goja is and why we use it

Before deploying anything, we want a tight feedback loop. Distlang can run this Worker locally by starting a small HTTP server and routing incoming requests into default.fetch.

The local runtime in Phase 0 is powered by Goja. Goja is a JavaScript engine implemented in Go, which means Distlang can execute JavaScript Workers directly inside the Distlang CLI without depending on Node.js. At this stage, the goal is simple: one binary that can compile your Worker-shaped module and execute it immediately, so we can iterate on semantics and portability quickly.

From the repo’s examples/helloworld/ directory:

make run

Then, in another terminal:

curl -i http://127.0.0.1:5656

Here is the response from my local run:

HTTP/1.1 200 OK
Date: Fri, 06 Mar 2026 21:12:17 GMT
Content-Length: 13
Content-Type: text/plain; charset=utf-8

Hello Worker!

From one source file to a Cloudflare Worker

Once the Worker runs locally, the next step is to turn the same source file into something Cloudflare can run. Distlang’s build step generates platform artifacts under dist/, including a Cloudflare Worker entrypoint and the Wrangler configuration needed to run it with Cloudflare’s tooling.

make build

That will produce outputs in examples/helloworld/dist/cloudflare/ (including worker.js and wrangler.toml). These files are generated so they can be driven directly by Wrangler, keeping the deploy story aligned with how Cloudflare expects Workers projects to behave.

To run the generated Worker under Wrangler locally:

make dev

This starts Wrangler’s local server. Here is what I see from a local run (trimmed to the interesting lines):

wrangler dev

wrangler 4.71.0
----------------
Starting local server...
[wrangler:info] Ready on http://localhost:8787

And hitting that local dev server returns the same body:

curl -i http://127.0.0.1:8787/
HTTP/1.1 200 OK
Content-Length: 13
Content-Type: text/plain;charset=UTF-8

Hello Worker!

And to deploy it, you first scaffold the local Cloudflare credential file:

make cloudflare-init

On my machine this prints:

../../bin/distlang target init --target=cloudflare --path=.
Skipped existing file targets/cloudflare/cloudflare.env.example
Skipped existing file targets/cloudflare/cloudflare.env
Initialized cloudflare target in targets/cloudflare

Fill in examples/helloworld/targets/cloudflare/cloudflare.env (created from the template), then deploy:

make deploy

Here is the output from a successful deploy run (trimmed slightly):

wrangler deploy

wrangler 4.71.0
----------------
ERROR Failed to fetch auth token: 400 Bad Request

Attempting to login via OAuth...
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth?...
Successfully logged in.

Uploaded index
Deployed index triggers
  https://index.georgethomas.workers.dev
Current Version ID: 9583b635-9726-451f-88a8-a44465eef380

And if you curl the deployed Worker, you should see the same response body:

curl -i https://index.georgethomas.workers.dev
HTTP/2 200
content-type: text/plain;charset=UTF-8
content-length: 13

Hello Worker!

Why this matters for platform independence

Cloudflare is the first target, but it’s not the destination. The larger intent of Distlang is to make “where code runs” a build choice rather than an application rewrite. This HelloWorld is small by design: it gives us a concrete place to nail down the Worker execution model, learn where platforms differ, and harden our compiler and runtime so the same source program can be carried to more environments over time.