Workers PHP

Laravel, running inside Cloudflare Workers.
PHP 8.5.2 in a V8 isolate, in every Cloudflare location.

Laravel v13.25.0 on PHP 8.5.2, rendered inside a V8 isolate

How Laravel maps to Cloudflare

Standard Laravel calls on the left. What actually runs them on the right.

Database

Eloquent works unchanged. Queries run on D1, where writes are serialized.

$chirp = Chirp::create(['message' => $text]);

Cache

The kv store reads from Workers KV at the edge. The do store runs on Durable Object shards for atomic counters and locks.

Cache::store('kv')->remember('stats', 60, fn () => ...);
Cache::store('do')->increment('clicks');

Files

Uploads store to R2. Downloads are served from the bucket without waking PHP. Try it: attach a photo to a chirp below.

$path = $request->file('photo')->store('photos', 'r2');

Queues

Jobs dispatch into Cloudflare Queues and run on a consumer, with native retries.

ProcessUpload::dispatch($chirp);

Realtime

Events broadcast through a Durable Object speaking the Pusher protocol. Stock Laravel Echo connects to it.

broadcast(new ChirpCreated($chirp));

Echo.channel('chirps').listen('.chirp.created', ...);

Scheduler

Closures and queued jobs run on Cron Triggers.

Schedule::call(fn () => ...)->everyFifteenMinutes();

Global counter

8
Laravel
Cache::store('do')->increment()
Cloudflare
one Durable Object shard holds this number
Guarantee
atomic. Every click from every tab lands exactly once, and every open tab updates live.
Observed
click to measure the round trip

Queue round trip

Laravel
dispatch(new DemoJob)
Path
request, Cloudflare Queue, consumer, WebSocket, this page
Guarantee
durable, at least once. About 2 seconds for the whole loop.
Observed
idle

Rate limiting

Laravel
throttle:5,1 middleware
Cloudflare
the counter behind it is a Durable Object shard
Guarantee
atomic across every isolate. Five requests a minute, then a real 429, no matter how the traffic spreads.
Observed
5 of 5 remaining this minute

KV cache and the scheduler

Laravel
Cache::store('kv')->remember(..., 60)
Value
computed 1 second ago by PHP 8.5.2, served from KV since
Scheduler
scheduled housekeeping ran 12 minutes ago via Schedule::call()

Live chirps

rows from D1, delivered by broadcast()

New posts appear without a refresh. Register and post one from another tab.

Chrome User 55 minutes ago

Chrome end-to-end test: this chirp and its photo went through the new @workersphp packages

Probe 2c303ab6 1 hour ago

probe 2c303ab6 boundary-lookalike ------ INTACT-2c303ab6-END

Probe 5ffffe6d 2 hours ago

probe 5ffffe6d boundary-lookalike ------ INTACT-5ffffe6d-END

Probe ba8d8962 2 hours ago

probe ba8d8962 boundary-lookalike ------ INTACT-ba8d8962-END

Probe 9ec4124b 3 hours ago

probe 9ec4124b boundary-lookalike ------ INTACT-9ec4124b-END

Under the hood

InterpreterPHP 8.5.2 compiled to wasm with JSPI and native wasm exceptions. Cold start is about 1 second.
Filesystemlazy zip-backed. The app is never extracted; files hydrate on first read.
Compile stepOPcache and Blade are pre-compiled at build time and shipped in the bundle.
Bindingsa single C function bridges PHP to KV, R2 and Durable Objects.
WebSocketsa Durable Object speaks the Pusher protocol, so stock Laravel Echo connects.

Workers PHP is a community project. It is not affiliated with or endorsed by Cloudflare or Laravel. Everything on this page, including the HTML itself, was produced by PHP running in a V8 isolate.