A small Ruby runtime for a very large edge

Ruby at the edge. The web you know.

Write a Rack-style application in PicoRuby. Compile it to WebAssembly. Run it inside Cloudflare Workers, close to every request.

REQUEST /hello EDGE READY
01 Cloudflare Request
02 Wasm ABI v3
03 PicoRuby Rack app
class App
  def self.call(env)
    [200, { "content-type" => "text/plain" },
      ["Hello from the edge"]]
  end
end
ruby bytecode loaded 200 OK   ·  12ms
Rackprotocol adapter
JSPIasync host bridge
Wasmcompact runtime
1 VMper request

01 — THE POSSIBILITY

Ruby ergonomics.
Edge-native reach.

PicoRuby brings a compact Ruby implementation to WebAssembly. The adapter connects familiar Ruby application shapes to Cloudflare’s global runtime and request-scoped platform bindings.

A

Keep the Ruby shape

A familiar call(env) entrypoint and a Rack response tuple let application code stay recognizably Ruby.

B

Reach the platform

Use D1, KV, R2, Workers AI, Vectorize, Queues, Durable Objects, Access, and Web Crypto from request-scoped Ruby wrappers.

C

Stay intentionally small

Precompiled bytecode, one VM per request, and explicit compatibility boundaries make the runtime understandable and testable.

02 — GETTING STARTED

One command to a new edge app.

Install the generator gem and create a minimal Worker project. The CLI writes the Ruby app, build configuration, Worker entrypoint, package manifests, and Wrangler configuration for you.

Ruby ≥ 3.2Node.jsEmscripten ≥ 5.0.0PicoRuby
Template & CLI repository
quickstart.sh
  1. 01gem install picoruby-cloudflare-template
  2. 02picoruby-cloudflare new hello-edge
  3. 03cd hello-edge
    bundle install && npm install
  4. 04export PICORUBY_ROOT=/path/to/picoruby
    npm run dev
Ready on http://localhost:8787

03 — RACK & SINATRA

A narrow bridge,
built on purpose.

The runtime implements the Rack application protocol—an environment Hash in, a [status, headers, body] tuple out. It is not the complete CRuby Rack distribution.

Read the compatibility contract
class App
  def self.call(env)
    name = env["PATH_INFO"].split("/").last
    [200,
      { "content-type" => "text/plain" },
      ["Hello, #{name}!"]]
  end
end

Rackup::Handler::CloudflareWorker.run(App)
Runtime contractCURRENT
Buffered request bodies
Supported
Headers & cookies
Supported
Sinatra routing
Compatibility profile
Host-owned AI / R2 streams
Supported
config.ru / Rack::Builder
Not provided by server
Ruby-generated streaming
Future work

The Sinatra profile intentionally disables sessions, rack-protection, logging middleware, static files, templates, and development reloading.

04 — CLOUDFLARE BINDINGS

Platform primitives,
Ruby syntax.

Bindings stay in the Worker env. The request receives typed Ruby wrappers through env["cloudflare.env"], with asynchronous calls bridged by JSPI.

Open the complete binding guide
DATABASE API details

Prepare. Bind. Run.

Keep SQL and values separate with an explicit prepared-statement flow.

VECTORIZE

Semantic search

Query, insert, upsert, inspect, and delete vectors using JSON-compatible values.

QUEUES

Producers & consumers

Send UTF-8 messages and process batches with ack, retry, and Rack-style middleware.

DURABLE OBJECTS

JSON object state

Store JSON-compatible POJOs in named Durable Object instances.

ACCESS

Identity middleware

Resolve Cloudflare Access identity and place it in the Rack environment.

WEB CRYPTO

Secure randomness

Use Web Crypto-backed random bytes and AES-GCM instead of pseudo-randomness.

FETCH + ENV

Native host access

Make buffered HTTP calls and read variables or secrets from request scope.

05 — EXAMPLES

See the pieces
working together.

The repository includes runnable applications that combine PicoRuby, Sinatra, Static Assets, and Cloudflare resources.