Preface
Why not develop Cloudflare Workers services using Ruby?
This web book is a hands-on guide to Uzumibi, a framework for developing edge services with Ruby. You'll learn its core features step by step as you build real projects.
Uzumibi is powered by mruby/edge, an implementation of mruby. The resulting artifacts are tiny — for typical use cases, they can be under 500 KiB even after compression.
We hope this book opens up a new frontier for you at the intersection of Ruby and the edge.

Introduction
Before discussing Uzumibi, let's first organize the concepts around mruby/edge, the mruby implementation that serves as Uzumibi's foundation. After that, we'll provide an overview of Uzumibi itself.
What is mruby/edge
mruby/edge is a lightweight mruby implementation specialized for WebAssembly (Wasm) environments. It leverages the bytecode specification of mruby, a lightweight Ruby VM, and was developed with the goal of running efficiently in edge computing and serverless environments.
What is mruby
mruby is a lightweight implementation of the Ruby language designed to run in embedded environments and resource-constrained systems. It is primarily developed under the leadership of Yukihiro Matsumoto, the creator of Ruby. Compared to CRuby (the standard Ruby implementation), mruby has a smaller binary size and lower memory usage, making it suitable for embedding in various environments such as IoT devices and game engines.
Recently, other implementations compatible with mruby's bytecode have been developed and are gaining attention, such as the even smaller mruby/c and PicoRuby, which offers a more practical embedded ecosystem.
Features of mruby/edge
mruby/edge is a re-implementation of the VM that executes mruby bytecode (.mrb files) written in Rust. It has the following features:
- First-class WebAssembly support: Designed to generate portable Wasm code. Currently supports compilation to
wasm32-unknown-unknownandwasm32-wasip1targets, running on browsers, Wasmtime, Cloudflare Workers, Fastly Compute@Edge, and various other WASM runtimes. - Rust implementation: Since the VM is written in Rust, it offers high memory safety and smooth compilation to Wasm.
- mruby 3.2.0 compatibility: Supports opcodes from mruby 3.2.0 through 3.4.0, enabling use of basic Ruby syntax and data types.
- SharedMemory: Provides a mechanism for efficient data exchange with the host environment (JavaScript, etc.) by utilizing Wasm's linear memory.
From mruby Code to WASM
The flow of converting Ruby code to Wasm with mruby/edge is as follows:
Ruby source code (.rb)
↓ Compile with mruby compiler (mrbc, mruby-compiler2, etc.)
mruby bytecode (.mrb)
↓ Embed in Rust binary
↓ Compile to Wasm with cargo
Wasm module (.wasm)
This Wasm module can run in browsers. Additionally, by executing it on edge platforms such as Cloudflare Workers or Fastly, applications written in Ruby can be run at the edge.
It is also possible to embed mruby-compiler2 into Rust to directly execute Ruby scripts with mruby/edge. You can try it out on the Playground.
https://mrubyedge.github.io/playground/
Supported Ruby Features
The following Ruby language features are supported in mruby/edge:
- Basic operations (arithmetic, comparison)
- Conditional branching (
if/elsif/else,case/when) - Method definition and recursive calls
- Class definition and instance variables
attr_readerdeclarations- Global variables (
$var) - Arrays (
Array), Hashes (Hash), Strings (String) - Range objects (
Range) - Blocks and iterators
- Exception handling (
raise/rescue) - String
unpack/pack(binary data processing)
The specific supported methods can be checked in the COVERAGE.md file. It may also be useful to have AI reference this file.
Additionally, the following libraries are available as mrubyedge gems:
mruby-randommruby-regexpmruby-mathmruby-serde-jsonmruby-time
Summary of mruby/edge
mruby/edge plays a crucial role as the foundation of the Uzumibi framework, enabling Ruby-written web application logic to run in edge environments.
What is Uzumibi
Uzumibi is a lightweight framework for building web applications in Ruby on edge computing platforms, built on top of mruby/edge.
The name "Uzumibi" is inspired by the popular edge framework Hono. Hono + Embedded (埋まっている / "buried") = Uzumibi (うずみび / "buried embers") 😅
Overview of Uzumibi
Uzumibi is a web application framework that allows you to define routing using a Sinatra-like DSL. You can write applications that handle HTTP requests with Ruby code like the following:
class App < Uzumibi::Router
get "/" do |req, res|
res.status_code = 200
res.headers = {
"content-type" => "text/plain",
"x-powered-by" => "#{RUBY_ENGINE} #{RUBY_VERSION}"
}
res.body = "It works!\n"
res
end
get "/greet/to/:name" do |req, res|
res.status_code = 200
res.headers = {
"content-type" => "text/plain",
}
res.body = "Hello, #{req.params[:name]}!!\n"
res
end
end
$APP = App.new
How It Works
Uzumibi applications operate in a two-layer architecture:
- Wasm layer (Rust + mruby/edge): Ruby code is compiled into mruby bytecode and embedded in a Wasm module. Request processing is handled by Ruby code running on the mruby/edge VM.
- Platform layer (JavaScript / Rust): Glue code that bridges the edge platform's native APIs with the Wasm module. It handles binary serialization of HTTP requests/responses.
The request flow looks like this:
Client
→ Edge platform
→ Glue code (JS/Rust) serializes request to binary
→ Ruby code executes on mruby/edge VM inside WASM module
→ Response is deserialized from binary
→ Response returned to client
Routing
Uzumibi's router supports the following HTTP methods:
getpostputdeleteheadoptions
URL paths can include dynamic parameters (:name) and wildcards (*). Parameters are accessible via req.params, which is a Hash.
# Dynamic parameter example
get "/users/:id" do |req, res|
user_id = req.params[:id]
# ...
end
In this book, we refer to the Ruby blocks defined with get, post, etc. as "route handlers".
Request Object
The req object (Uzumibi::Request) passed to the route handler block holds the following information:
req.method- HTTP method (GET, POST, etc.)req.path- Request pathreq.query- Query stringreq.headers- Request headers (Hash)req.body- Request bodyreq.params- A Hash that integrates URL parameters, query parameters, and form data
Response Object
The res object (Uzumibi::Response) is used to construct the response by setting the following properties:
res.status_code- HTTP status code (integer)res.headers- Response headers (Hash)res.body- Response body (string)
The route handler block must always return the res object.
External Service Integration
Uzumibi also supports access to external services provided by edge platforms. On Cloudflare Workers, the following are available:
Uzumibi::Fetch- Call external HTTP APIsUzumibi::KV- Key-Value store using Durable ObjectsUzumibi::Queue- Asynchronous messaging with Cloudflare Queues
These features are explained in detail in later chapters.
Note: As of March 14, 2026, external services are not available on platforms other than Cloudflare Workers. Support for other platforms will be added progressively. Pull requests are always welcome!
Project Setup and Hello World
In this chapter, we'll get Uzumibi up and running by installing the necessary tools, creating a hello world project, and verifying that everything works.
Installing uzumibi-cli
To start developing with Uzumibi, you first need to install uzumibi-cli and its prerequisite tools.
Prerequisites
The following tools must be installed beforehand.
Rust Toolchain
The Rust compiler is required to build Uzumibi projects. Install it using rustup:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
After installation, add the WASM target:
rustup target add wasm32-unknown-unknown
Verify the version:
$ rustc --version
rustc 1.93.1 (01f6ddf75 2026-02-11)
Node.js and pnpm
For Cloudflare Workers, Node.js is required for development and deployment with Wrangler.
# Installing Node.js (example using a version manager)
# With fnm
fnm install --lts
# With nvm
nvm install --lts
# Installing pnpm
npm install -g pnpm
Verify the versions:
$ node --version
v25.6.1
$ pnpm --version
10.29.3
Wrangler CLI
A CLI tool used for developing and deploying Cloudflare Workers. It will be automatically installed locally via pnpm install after project creation, but installing it globally can be convenient:
pnpm install -g wrangler
clang / Build Tools
The C compiler clang is required for building the mruby compiler (mruby-compiler2).
For macOS:
xcode-select --install
For Linux:
# Ubuntu/Debian
sudo apt-get install clang build-essential
# Fedora
sudo dnf install clang
Installing uzumibi-cli
uzumibi-cli is installed using Rust's package manager cargo:
cargo install 'uzumibi-cli@^0.6'
Once installation is complete, verify the version:
$ uzumibi --version
uzumibi-cli 0.6.1
You can view the help to see available commands:
$ uzumibi --help
With this, your development environment is ready.
Creating a Project
Use the uzumibi new command to create a project for Cloudflare Workers.
Generating the Project
Create a project named hello-uzumibi with the following command:
uzumibi new --template cloudflare hello-uzumibi
Running this command will create a project directory and generate the necessary files:
Creating project 'hello-uzumibi'...
generate hello-uzumibi/.gitignore
generate hello-uzumibi/Cargo.toml
generate hello-uzumibi/package.json
generate hello-uzumibi/vitest.config.js
generate hello-uzumibi/wrangler.jsonc
generate hello-uzumibi/lib/app.rb
generate hello-uzumibi/public/assets/index.html
generate hello-uzumibi/src/index.js
generate hello-uzumibi/wasm-app/Cargo.toml
generate hello-uzumibi/wasm-app/build.rs
generate hello-uzumibi/wasm-app/src/lib.rs
✓ Successfully created project from template 'cloudflare'
Run 'cd hello-uzumibi' to get started!
Project Directory Structure
The generated project has the following structure:
hello-uzumibi/
├── Cargo.toml # Rust workspace configuration
├── package.json # Node.js dependencies and scripts
├── wrangler.jsonc # Wrangler (Cloudflare Workers CLI) configuration
├── lib/
│ └── app.rb # Ruby application code (main)
├── public/
│ └── assets/... # Static assets (HTML, CSS, images, etc.)
├── src/
│ └── index.js # JavaScript glue code (entry point)
└── wasm-app/
├── Cargo.toml # WASM crate configuration
├── build.rs # Build script (compiles Ruby code)
├── src/
│ └── lib.rs # Rust code for the WASM module
└── .cargo/
└── config.toml # Cargo target settings (may not exist)
Role of Each File
lib/app.rb
This is the main file that developers edit. You write Uzumibi's routing and request handling logic in Ruby here.
src/index.js
The entry point for Cloudflare Workers. It receives HTTP requests, serializes them to binary format and passes them to the WASM module, then deserializes the response and returns it to the client. Normally, you don't need to edit this file.
wasm-app/
A Rust crate for compiling Ruby code into mruby bytecode and packaging it as a WASM module. Normally, you don't need to edit these files.
build.rscontains configuration to compilelib/app.rbinto mruby bytecode (.mrb) at build time.src/lib.rshandles mruby/edge VM initialization and export function definitions.
wrangler.jsonc
The Cloudflare Workers configuration file. It contains the application name, static asset settings, and more.
{
"name": "hello-uzumibi",
"main": "src/index.js",
"compatibility_date": "2025-12-30",
"assets": {
"directory": "./public",
"binding": "ASSETS"
}
}
package.json
Defines npm/pnpm scripts and dependencies.
{
"scripts": {
"deploy": "wrangler deploy",
"dev": "cargo build --package hello-uzumibi --target wasm32-unknown-unknown --release && cp -v -f target/wasm32-unknown-unknown/release/hello_uzumibi.wasm src/ && wrangler dev",
"start": "wrangler dev",
"test": "vitest"
}
}
The dev script performs both the Rust build (WASM compilation) and Wrangler dev server startup in one step.
Installing Dependencies
Navigate to the project directory and install the Node.js dependencies:
cd hello-uzumibi
pnpm install
This installs development tools including Wrangler locally within the project.
Implementing a Hello World Application
Now that the project is created, let's implement an actual application. Uzumibi allows you to work with both Ruby code (lib/app.rb) and a static frontend (public/ directory).
Frontend Implementation
First, let's place a static HTML file in the public/ directory. Create public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello Uzumibi</title>
<style>
body {
font-family: sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 0 20px;
}
#result {
margin-top: 20px;
padding: 15px;
background: #f0f0f0;
border-radius: 5px;
}
</style>
</head>
<body>
<h1>Hello Uzumibi!</h1>
<p>Building Cloudflare Workers with Ruby</p>
<button id="greetBtn">Call API</button>
<div id="result"></div>
<script>
document.getElementById('greetBtn').addEventListener('click', async () => {
const res = await fetch('/api/hello');
const text = await res.text();
document.getElementById('result').textContent = text;
});
</script>
</body>
</html>
Files placed in the public/ directory are automatically served by Cloudflare Workers' static asset feature.
API Implementation
Next, edit lib/app.rb to implement the API endpoints. Replace the default generated code with the following:
class App < Uzumibi::Router
# Root path delegates to static assets (public/index.html)
get "/" do |req, res|
fetch_assets
end
# Simple API endpoint
get "/api/hello" do |req, res|
res.status_code = 200
res.headers = {
"content-type" => "text/plain",
"x-powered-by" => "#{RUBY_ENGINE} #{RUBY_VERSION}"
}
res.body = "Hello from Uzumibi! Running on #{RUBY_ENGINE} #{RUBY_VERSION}\n"
res
end
# Greeting API with dynamic parameters
get "/api/greet/:name" do |req, res|
name = req.params[:name]
res.status_code = 200
res.headers = {
"content-type" => "application/json",
}
res.body = JSON.generate({ message: "Hello, #{name}!" })
res
end
# POST request handling
post "/api/echo" do |req, res|
res.status_code = 200
res.headers = {
"content-type" => "text/plain",
}
res.body = "Received: #{req.body.inspect}\n"
res
end
end
$APP = App.new
Code Walkthrough
Routing
Define routes using class methods like get and post within a class that inherits from Uzumibi::Router:
class App < Uzumibi::Router
get "/path" do |req, res|
# Handler logic
end
end
Each route handler block receives two arguments: req (request) and res (response).
Serving Static Assets
get "/" do |req, res|
fetch_assets
end
Calling the fetch_assets method delegates the request to the static assets in the public/ directory. This causes public/index.html to be returned for the / path.
Note that if you define a handler for "/file" and a request comes in for /file, public/file.html will be returned if it exists. Be aware that the file extension is automatically appended.
Building a Response
Set status_code, headers, and body on the response object, then return res:
get "/api/hello" do |req, res|
res.status_code = 200
res.headers = {
"content-type" => "text/plain",
}
res.body = "Hello!\n"
res # Always return res
end
Dynamic Parameters
Including :parameter_name in the URL path captures that path segment as a dynamic parameter. Access it through the req.params Hash:
get "/api/greet/:name" do |req, res|
name = req.params[:name]
# ...
end
Request Body
The body of POST requests and similar can be accessed synchronously via req.body. If the request's content-type is form data (application/x-www-form-urlencoded) or JSON data (application/json), it is automatically parsed, and you can access the data through req.params as well.
The $APP Global Variable
$APP = App.new
In Uzumibi 0.6.x, the convention is to assign the application instance to the global variable $APP at the end. This variable is referenced from the Rust code on the Wasm side, so it must always be set.
Starting the Dev Server
Once the application code is written, let's start the development server to verify it works.
Launching the Dev Server
Start the development server with the following command:
pnpm run dev
This command internally executes the following steps in sequence:
- Rust build: Runs the
cargocommand to compilelib/app.rbinto mruby bytecode and then generate a Wasm module (.wasm). - Wasm file copy: Copies the built
.wasmfile to thesrc/directory. - Wrangler dev startup: Runs
wrangler devto start the local development server.
The first build may take several minutes as it needs to download and compile Rust crates. Subsequent builds will be faster due to incremental compilation.
When the build is complete, you'll see a message like this:
⛅️ wrangler 4.73.0
───────────────────
Your Worker has access to the following bindings:
Binding Resource Mode
env.ASSETS Assets local
...
⎔ Starting local server...
[wrangler:info] Ready on http://localhost:8787
Verifying Operation
Once the development server is running, verify the operation using a browser or curl.
Browser Verification
Access http://localhost:8787 in your browser to see the contents of public/index.html. Clicking the "Call API" button will display the response from the /api/hello endpoint.
You can adjust the JavaScript in the HTML to call other endpoints and check their output as well.
curl Verification
Let's call the API endpoints using curl:
# Root path (static assets)
$ curl http://localhost:8787/
<!DOCTYPE html>
<html lang="en">
...
# API endpoint
$ curl http://localhost:8787/api/hello
Hello from Uzumibi! Running on mruby/edge 3.2.0
# Dynamic parameters
$ curl http://localhost:8787/api/greet/World
{"message": "Hello, World!"}
# POST request
$ curl -X POST -d "test data" http://localhost:8787/api/echo
Received: test data
Reflecting Code Changes
If you modify lib/app.rb, the current version of Uzumibi does not support automatic reloading. Since a Wasm rebuild is required, stop the development server (Ctrl+C) and run pnpm run dev again:
# Stop with Ctrl+C
# Edit code
# Restart
pnpm run dev
Troubleshooting
Build Error: clang not found
clang is required for building the mruby compiler. On macOS, install it with xcode-select --install; on Linux, use apt install clang.
Build Error: wasm32-unknown-unknown target not found
The Wasm target may not have been added.
rustup target add wasm32-unknown-unknown
Wrangler Authentication Error
If this is your first time using Wrangler, you may need to log in:
npx wrangler login
Port Conflict
If the default port 8787 is in use by another process, Wrangler will automatically use a different port. Check the URL displayed in the console output.
Deployment
Once you've verified your application works on the development server, let's deploy it to Cloudflare Workers.
Preparing a Cloudflare Account
You need a Cloudflare account to deploy. If you don't have one yet, sign up at the Cloudflare dashboard. You can use Cloudflare Workers on the free plan.
Logging in to Wrangler
Log in to your Cloudflare account from the Wrangler CLI:
npx wrangler login
A browser window will open asking you to authenticate with Cloudflare. Once authentication is complete, a login success message will appear in the terminal.
Building WASM
Before deploying, you need to build the WASM module. If you've already run pnpm run dev at least once, the built .wasm file should already be in the src/ directory. If you haven't built yet, you can run just the build with the following commands:
cargo build --package hello-uzumibi --target wasm32-unknown-unknown --release
cp target/wasm32-unknown-unknown/release/hello_uzumibi.wasm src/
Running the Deployment
Deploy to Cloudflare Workers with the following command:
pnpm run deploy
This command internally runs wrangler deploy.
When the deployment starts, you'll see a message like this:
⛅️ wrangler 4.73.0
───────────────────
🌀 Building list of assets...
✨ Read 3 files from the assets directory /Users/udzura/zenn-wip/hello-uzumibi/public
🌀 Starting asset upload...
Pay attention to the size display in the logs. Artifacts generated by Uzumibi are approximately 650 KiB before compression and around 200 KiB with gzip compression:
Total Upload: 655.99 KiB / gzip: 204.28 KiB
On Cloudflare Workers' free plan, you can upload assets up to 3 MB, and the recommended configuration is to keep compressed size under 1 MB.
While larger applications may be difficult to serve on Cloudflare Workers, Uzumibi and mruby/edge applications are designed to provide minimal functionality to keep the size as small as possible. This makes them very advantageous for edge application development.
The URL displayed at the end will allow you to access your deployed application:
Uploaded hello-uzumibi (14.81 sec)
Deployed hello-uzumibi triggers (7.49 sec)
https://hello-uzumibi.XXXXXX.workers.dev
Current Version ID: b7bcc75c-e557-4c39-b643-xxxxxxxx
Verifying the Deployment
Access https://hello-uzumibi.<your-subdomain>.workers.dev/ in your browser to see the HTML page you created earlier.
wrangler.jsonc Configuration
The deployed Worker's name and settings are managed in wrangler.jsonc:
{
"name": "hello-uzumibi", // Worker name (becomes the URL subdomain)
"main": "src/index.js", // Entry point
"compatibility_date": "2025-12-30",
"assets": {
"directory": "./public", // Static assets directory
"binding": "ASSETS"
}
}
If you want to change the Worker name, edit the "name" field and redeploy.
Custom Domain Configuration
By default, the application is deployed to a *.workers.dev domain, but you can also configure a custom domain. Set it up from the Cloudflare dashboard under "Workers & Pages", or add routes to wrangler.jsonc.
See the Cloudflare Workers documentation for details.
Chapter Summary
In this chapter, we walked through the basic development workflow for a Cloudflare Workers application using Uzumibi.
What We Learned
-
Installing uzumibi-cli: We prepared prerequisite tools including the Rust toolchain, Node.js/pnpm, and Wrangler, then installed the CLI with
cargo install uzumibi-cli. -
Creating a project: We generated a project with the
uzumibi new --template cloudflarecommand and reviewed the directory structure and the role of each file. -
Implementing the application:
- Created a static frontend page in
public/index.html. - Implemented API endpoints in Ruby in
lib/app.rb. - Learned the basic DSL of
Uzumibi::Router(get,post, dynamic parameters, etc.).
- Created a static frontend page in
-
Development server: Started the local development server with
pnpm run devand verified operation using a browser and curl. -
Deployment: Deployed to Cloudflare Workers with
pnpm run deployand ran the application at a public URL.
In the following chapters, we'll cover the external service integration features (Fetch, Durable Object, Queue) available in Uzumibi on Cloudflare Workers.
Uzumibi and External Services
This chapter provides an overview of the external services supported by Uzumibi on Cloudflare Workers.
External Services Available on Uzumibi with Cloudflare Workers
On Cloudflare Workers, you can access external Web APIs through JavaScript's fetch() function, as well as various services provided by Cloudflare.
Uzumibi provides APIs for using some of these services from Ruby.
To use external service integration, specify the --features enable-external option when creating a project:
uzumibi new --template cloudflare --features enable-external my-app
Currently, Uzumibi on Cloudflare Workers supports the following three external services:
Fetch
Uzumibi::Fetch is an API for making external HTTP requests from within a Worker. Use it when calling external REST APIs or web services.
# Basic usage
response = Uzumibi::Fetch.fetch("https://api.example.com/data")
# response.status_code => 200
# response.body => Response body
# response.headers => Response headers (Hash)
The Uzumibi::Fetch.fetch method takes the following four arguments:
| Argument | Type | Description |
|---|---|---|
url | String | Request URL (required) |
method | String | HTTP method (defaults to "GET") |
body | String | Request body (defaults to empty string) |
headers | Hash[String, String] | Request headers (defaults to none) |
The return value is a Uzumibi::Response object with status_code, headers, and body.
Internally, it executes asynchronous HTTP requests through JavaScript's fetch() API.
Note: Functions like
fetch()are asynchronous at the JavaScript level. To call asynchronous operations through Wasm, Uzumibi uses theasyncifyfeature from binaryen and theasyncify-wasmJavaScript library. Due to these libraries, the Wasm binary is slightly larger when external service integration is enabled.
Durable Object
Uzumibi::KV is a Key-Value store that uses Cloudflare Durable Objects. It allows you to persistently store data across requests.
# Save a value
Uzumibi::KV.set("key", "value")
# Get a value
value = Uzumibi::KV.get("key")
# => "value"
# Non-existent key
value = Uzumibi::KV.get("unknown")
# => nil
Durable Objects are Cloudflare Workers' stateful storage feature. In Uzumibi, a Durable Object class named UzumibiKVObject is automatically configured, and data is persisted using SQLite-based storage.
| Method | Arguments | Return Value | Description |
|---|---|---|---|
Uzumibi::KV.get(key) | key: String | String or nil | Get the value for a key |
Uzumibi::KV.set(key, value) | key: String, value: String | true | Save a value for a key |
Queue
Uzumibi::Queue is an API for sending messages to Cloudflare Queues. It can be used for asynchronous background processing. When using Queues, you need to create a Queue in advance through the Cloudflare dashboard or similar.
# Send a message
Uzumibi::Queue.send("UZUMIBI_QUEUE", "Hello from queue!")
| Method | Arguments | Return Value | Description |
|---|---|---|---|
Uzumibi::Queue.send(queue_name, message) | queue_name: String, message: String | true | Send a message to the specified queue |
queue_name is the name of the queue binding defined in wrangler.jsonc. The implementation of the Queue receiver (Consumer) is explained in detail in Chapter 6.
Internal Behavior of External Service Features
Projects with external service integration enabled differ from standard projects in the following ways:
- Wasm module: The
enable-externalfeature is added towasm-app/Cargo.toml, incorporating Fetch/KV/Queue wrapper functions on the Rust side. - JavaScript glue code:
src/index.jsis replaced with a version that uses theasyncify-wasmlibrary, enabling asynchronous operations (await) inside Wasm. - wrangler.jsonc: Durable Object bindings and migration settings are added. Queue enablement needs to be configured manually.
In the following chapters, we'll introduce examples that actually use the external services.
Calling External Public APIs with Fetch
In this chapter, we'll create an application that calls external Web APIs using Uzumibi::Fetch.
Creating the Project
Create a new project with external service integration enabled:
uzumibi new \
--template cloudflare \
--features enable-external \
fetch-example
cd fetch-example
pnpm install
Selecting an API to Use
In this example, we'll use the freely available JSONPlaceholder API. This is a test API that returns dummy TODO data, user data, and more.
We'll primarily use the following endpoints:
GET https://jsonplaceholder.typicode.com/todos/1- Get a TODO by IDGET https://jsonplaceholder.typicode.com/todos?_limit=5- Get a list of TODOs (with a limit)
Calling the API
Edit lib/app.rb as follows:
class App < Uzumibi::Router
get "/" do |req, res|
fetch_assets
end
# Get a single TODO from the external API
get "/api/todo/:id" do |req, res|
id = req.params[:id]
api_url = "https://jsonplaceholder.typicode.com/todos/#{id}"
debug_console("Fetching: #{api_url}")
api_response = Uzumibi::Fetch.fetch(api_url)
res.status_code = api_response.status_code
res.headers = {
"content-type" => "application/json",
}
res.body = api_response.body
res
end
# Get a list of TODOs from the external API
get "/api/todos" do |req, res|
api_url = "https://jsonplaceholder.typicode.com/todos?_limit=5"
debug_console("Fetching: #{api_url}")
api_response = Uzumibi::Fetch.fetch(api_url)
res.status_code = api_response.status_code
res.headers = {
"content-type" => "application/json",
}
res.body = api_response.body
res
end
# Example of forwarding a POST request
post "/api/todo" do |req, res|
api_url = "https://jsonplaceholder.typicode.com/todos"
debug_console("Posting to: #{api_url}")
api_response = Uzumibi::Fetch.fetch(
api_url, "POST",
JSON.generate(req.body),
{"content-type" => "application/json"}
)
res.status_code = api_response.status_code
res.headers = {
"content-type" => "application/json",
}
res.body = api_response.body
res
end
end
$APP = App.new
Code Walkthrough
Forwarding GET Requests
api_response = Uzumibi::Fetch.fetch(api_url)
Simply passing a URL to Uzumibi::Fetch.fetch executes a GET request. The return value api_response is a Uzumibi::Response object that holds the response from the external API.
Forwarding POST Requests
api_response = Uzumibi::Fetch.fetch(api_url, "POST", req.body)
By specifying an HTTP method as the second argument and a request body as the third argument, you can send POST and other types of requests.
Specify header information such as authentication as a Hash in the fourth argument.
Debug Output
debug_console("Fetching: #{api_url}")
The debug_console method outputs debug messages to the Wrangler console (terminal). It is not displayed in the browser.
Verifying Operation
Start the development server:
pnpm run dev
Verify operation with curl:
# Get a single TODO
$ curl http://localhost:8787/api/todo/1
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
}
# Get a list of TODOs
$ curl http://localhost:8787/api/todos
[
{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
},
{
"userId": 1,
"id": 2,
"title": "quis ut nam facilis et officia qui",
"completed": false
},...
]
# POST request
$ curl -X POST -H "Content-Type: application/json" \
-d '{"title":"New Todo","completed":false,"userId":1}' \
http://localhost:8787/api/todo
{
"completed": false,
"title": "New Todo",
"userId": 1,
"id": 201
}
Debug messages like the following will appear in the Wrangler console:
[debug]: Fetching: https://jsonplaceholder.typicode.com/todos/1
We've implemented a sample application that calls external APIs from Uzumibi.
Chapter Summary
With Uzumibi::Fetch, you can easily integrate with external microservices and third-party APIs.
Saving Memos with Durable Object
In this chapter, we'll create a memo application that stores data persistently using Uzumibi::KV (based on Cloudflare Durable Objects).
Architecture Overview
Cloudflare Durable Objects is a service for managing stateful objects on Cloudflare Workers. While regular Workers are stateless (they don't retain state between requests), Durable Objects enable persistent data read/write operations.
In Uzumibi version 0.6.x, the Uzumibi::KV API wraps Durable Objects as a simple Key-Value store.
Client → Cloudflare Worker (Uzumibi)
↓ Uzumibi::KV.get/set
UzumibiKVObject (Durable Object)
↓
SQLite storage (persisted)
UzumibiKVObject is a Durable Object class defined in the JavaScript glue code. Internally, it uses the Durable Object's ctx.storage API (SQLite-based) to store data.
Creating the Project
Create a project with external service integration enabled:
uzumibi new \
--template cloudflare \
--features enable-external memo-app
cd memo-app
pnpm install
Check the generated wrangler.jsonc to see the automatically configured Durable Object bindings:
{
"durable_objects": {
"bindings": [
{
"name": "UZUMIBI_KV_DATA",
"class_name": "UzumibiKVObject"
}
]
},
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": [
"UzumibiKVObject"
]
}
]
}
Implementation
Edit lib/app.rb to create a simple memo save/retrieve API:
class App < Uzumibi::Router
get "/" do |req, res|
fetch_assets
end
# Get a memo
get "/api/memo/:key" do |req, res|
key = req.params[:key]
value = Uzumibi::KV.get(key)
if value
res.status_code = 200
res.headers = {
"content-type" => "application/json",
}
res.body = JSON.generate({
key: key,
value: value
})
else
res.status_code = 404
res.headers = {
"content-type" => "application/json",
}
res.body = JSON.generate({
error: "not found",
key: key
})
end
res
end
# Save a memo
post "/api/memo/:key" do |req, res|
key = req.params[:key]
value = req.body
debug_console("Saving memo: #{key} = #{value}")
Uzumibi::KV.set(key, value)
res.status_code = 201
res.headers = {
"content-type" => "application/json",
}
res.body = JSON.generate({
key: key,
value: value,
status: "saved"
})
res
end
end
$APP = App.new
Code Walkthrough
Getting a Value
value = Uzumibi::KV.get(key)
Uzumibi::KV.get returns the value for the specified key as a string. If the key doesn't exist, it returns nil.
Saving a Value
Uzumibi::KV.set(key, value)
Uzumibi::KV.set saves a key-value pair. Calling set again with the same key overwrites the value. Both keys and values are string types.
Verifying Operation
Start the development server:
pnpm run dev
Test saving and retrieving memos with curl:
# Save a memo
$ curl -X POST -d "Shopping list: milk, bread, eggs" \
http://localhost:8787/api/memo/shopping
{"key": "shopping", "value": "Shopping list: milk, bread, eggs", "status": "saved"}
# Get a memo
$ curl http://localhost:8787/api/memo/shopping
{"key": "shopping", "value": "Shopping list: milk, bread, eggs"}
# Non-existent key
$ curl http://localhost:8787/api/memo/unknown
{"error": "not found", "key": "unknown"}
# Update a memo
$ curl -X POST -d "Shopping list: milk, bread, eggs, butter" \
http://localhost:8787/api/memo/shopping
{"key": "shopping", "value": "Shopping list: milk, bread, eggs, butter", "status": "saved"}
Data stored in the Durable Object persists across Worker restarts and deployments.
Notes
- Both keys and values in
Uzumibi::KVare string types. If you want to store numbers or objects, convert them to JSON strings or similar before saving. - During local development (
wrangler dev), Durable Object data is saved in local storage within the project's.wrangler/directory. - When deployed to production, data is stored on Cloudflare's global network.
Communicating with Cloudflare Queue
Cloudflare Queues is a message queue service. It provides the basic message queuing pattern where a producer (sender) sends messages to a queue and a consumer (receiver) processes them asynchronously.
Queue Use Cases
Publisher
A Publisher (producer) is responsible for sending messages to a queue. In Uzumibi, you use the Uzumibi::Queue.send method to send messages.
Typical use cases include:
- Asynchronous background processing: Return a response to the user immediately while delegating time-consuming tasks (email sending, image conversion, data aggregation, etc.) to the queue.
- Event notification: Notify another Worker of events that occurred in one Worker (user registration, order completion, etc.) to trigger subsequent processing.
- Rate limit mitigation: Put requests to external APIs into a queue first, then process them sequentially on the consumer side in a controlled manner.
# Example: Send a welcome email asynchronously after user registration
post "/api/users" do |req, res|
# User registration processing (completes immediately)
# ...
# Delegate email sending to the queue (asynchronous)
Uzumibi::Queue.send("UZUMIBI_QUEUE", "welcome_email:#{user_email}")
res.status_code = 201
res.body = JSON.generate({status: "registered"})
res
end
Consumer
A Consumer is responsible for receiving and processing messages from the queue.
Note: In a standard Cloudflare project, the web application that sends to a Cloudflare Queue and the process that receives messages from the queue can be defined in the same Worker file. However, in Uzumibi 0.6.x, you need to generate a separate consumer-only application, so please keep this in mind.
In the Ruby code of the consumer application, you prepare a class that inherits from Uzumibi::Consumer and override the on_receive method to implement the processing logic.
Consumers have the following characteristics:
- Batch processing: Messages are received in batches (up to 10 messages, with a maximum wait time of 5 seconds).
- Retry functionality: Failed messages can be retried after a specified delay.
- Acknowledgment: Successfully processed messages are acknowledged with
ack!and removed from the queue.
class Consumer < Uzumibi::Consumer
def on_receive(message)
debug_console("Processing: #{message.body}")
# Acknowledge after successful processing
message.ack!
end
end
The Message object has the following attributes:
| Attribute | Type | Description |
|---|---|---|
message.id | String | Unique ID of the message |
message.timestamp | String | Timestamp when the message was sent (ISO 8601 format) |
message.body | String | Message body |
message.attempts | Integer | Number of delivery attempts so far |
The Message object also has the following methods:
| Method | Description |
|---|---|
message.ack! | Notify that message processing is complete and remove it from the queue |
message.retry(delay_seconds: N) | Redeliver the message after N seconds |
Queue Architecture and Setup
When building a Uzumibi application using Cloudflare Queues, you configure two Workers: a sender (Publisher) and a receiver (Consumer). This section explains the overall architecture and setup process.
Architecture
Client
↓ HTTP request
[Publisher Worker] (generated with enable-external feature)
↓ Uzumibi::Queue.send
[Cloudflare Queue]
↓ Message delivery
[Consumer Worker] (generated with queue feature)
↓ on_receive(message)
Message processing → ack! or retry
The sender and receiver operate as separate Workers, both bound to the same queue. The sender sends messages through the queues.producers binding, and the receiver receives messages through the queues.consumers binding.
Creating a Cloudflare Queue
First, you need to create a queue in Cloudflare Queues. Create one from the Cloudflare dashboard or using the Wrangler CLI:
$ npx wrangler queues create my-app-queue
...
⛅️ wrangler 4.73.0
───────────────────
🌀 Creating queue 'my-app-queue'
✅ Created queue 'my-app-queue'
Verify that the queue was created:
$ npx wrangler queues list
┌──────────────────────────────────┬───────────────┬─────────────────────────────┬─────────────────────────────┬───────────┬───────────┐
│ id │ name │ created_on │ modified_on │ producers │ consumers │
├──────────────────────────────────┼───────────────┼─────────────────────────────┼─────────────────────────────┼───────────┼───────────┤
│ 7941fbb9762d4a02b1a1c644XXXXXXXX │ my-app-queue │ 2026-03-14T12:48:00.918834Z │ 2026-03-14T12:48:00.918834Z │ 0 │ 0 │
└──────────────────────────────────┴───────────────┴─────────────────────────────┴─────────────────────────────┴───────────┴───────────┘
Project Structure
Two projects are needed for Queue communication:
- Sender project: Created with the
enable-externalfeature, sends messages usingUzumibi::Queue.send. - Receiver project: Created with the
queuefeature, receives and processes messages usingUzumibi::Consumer.
# Sender
uzumibi new --template cloudflare --features enable-external queue-publisher
# Receiver
uzumibi new --template cloudflare --features queue queue-consumer
Note: When the
queuefeature is enabled, theenable-externalfeature is also automatically enabled in the generated project.
wrangler.jsonc Configuration
Sender Configuration
In the sender's wrangler.jsonc, configure the queue binding in queues.producers. The default template has this commented out, so uncomment it to enable:
{
"queues": {
"producers": [
{
"binding": "UZUMIBI_QUEUE",
"queue": "my-app-queue"
}
]
}
}
binding is the name used to reference the queue in code, corresponding to the first argument of Uzumibi::Queue.send. queue specifies the actual queue name created in Cloudflare Queues.
Receiver Configuration
In the receiver's wrangler.jsonc, the queues.consumers queue binding is automatically configured from the project name. For this example, manually change it to the correct name:
{
"queues": {
"producers": [
{
"binding": "UZUMIBI_QUEUE",
"queue": "my-app-queue"
}
],
"consumers": [
{
"queue": "my-app-queue",
"max_batch_size": 10,
"max_batch_timeout": 5
}
]
}
}
Configure the following values as needed:
| Setting | Description |
|---|---|
queue | Name of the queue to receive from |
max_batch_size | Maximum number of messages to receive at once (default: 10) |
max_batch_timeout | Maximum wait time in seconds for a batch to fill (default: 5) |
Publisher Implementation
The publisher Worker (queue-publisher) receives HTTP requests and sends messages to a Cloudflare Queue.
Application Implementation
Edit lib/app.rb as follows:
class App < Uzumibi::Router
# Message sending API
post "/api/send" do |req, res|
message = req.body
if message == "" || message == nil
res.status_code = 400
res.headers = {
"content-type" => "application/json",
}
res.body = JSON.generate({ error: "message body is required" })
else
debug_console("Sending message to queue: #{message}")
Uzumibi::Queue.send("UZUMIBI_QUEUE", message)
res.status_code = 202
res.headers = {
"content-type" => "application/json",
}
res.body = JSON.generate({ status: "accepted", message: message })
end
res
end
# Example of enqueuing a task
post "/api/tasks/:task_type" do |req, res|
task_type = req.params[:task_type]
payload = req.body
# Send task type and payload in JSON format
queue_message = JSON.generate({ type: task_type, payload: payload })
debug_console("Enqueuing task: #{queue_message}")
Uzumibi::Queue.send("UZUMIBI_QUEUE", queue_message)
res.status_code = 202
res.headers = {
"content-type" => "application/json",
}
res.body = JSON.generate({ status: "queued", task_type: task_type })
res
end
end
$APP = App.new
Code Walkthrough
Sending a Message
Uzumibi::Queue.send("UZUMIBI_QUEUE", message)
The first argument of Uzumibi::Queue.send specifies the binding name configured in queues.producers in wrangler.jsonc. The second argument is the message body (string).
HTTP Status Code 202
Since enqueuing a message means starting asynchronous processing, we return HTTP status code 202 Accepted. The actual message processing is performed by the consumer Worker.
Verifying Operation
Start the development server and test message sending:
pnpm run dev
# Send a message
$ curl -X POST -d "Hello, Queue\!" http://localhost:8787/api/send
{"status": "accepted", "message": "Hello, Queue!"}
# Enqueue a task
$ curl -X POST -d "user@example.com" \
http://localhost:8787/api/tasks/send_email
{"status": "queued", "task_type": "send_email"}
During local development, queue messages are actually sent to a dummy server on localhost. Debug messages will be displayed in the Wrangler console:
[debug]: Sending message to queue: Hello, Queue!
[debug]: Enqueuing task: {"type": "send_email", "payload": "user@example.com"}
Deploy for Integration Testing
After basic verification, deploy to the remote Cloudflare Worker with the following command:
pnpm run deploy
After deployment, perform a quick operational check:
curl -X POST -d "Hello, Production Queue\!" \
http://queue-publisher.<ID>.workers.dev/api/send
{"message":"Hello, Production Queue!","status":"accepted"}
Consumer Implementation
The consumer Worker receives messages from a Cloudflare Queue and processes them. In Uzumibi, you inherit from the Uzumibi::Consumer class and implement processing in the on_receive method.
Project Structure
When the queue feature is enabled, the following file is generated instead of the standard lib/app.rb:
lib/consumer.rb- Consumer Ruby code
Additionally, consumer-specific Wasm export functions (uzumibi_initialize_message, uzumibi_start_message) are added to wasm-app/src/lib.rs.
queue-consumer/
├── lib/
│ └── consumer.rb # Queue consumer processing
├── src/
│ └── index.js # JS glue code (handles both HTTP and Queue)
├── wasm-app/
│ ├── build.rs # Compiles both app.rb and consumer.rb
│ └── src/
│ └── lib.rs # Wasm (exports both HTTP and Queue processing)
├── wrangler.jsonc
└── package.json
The consumer Worker is dedicated to processing Queue messages.
Verifying wrangler.jsonc
The consumer's wrangler.jsonc contains queues.consumers configuration. Double-check that the queue name matches the sender:
{
"queues": {
"producers": [
{
"binding": "UZUMIBI_QUEUE",
"queue": "my-app-queue"
}
],
"consumers": [
{
"queue": "my-app-queue",
"max_batch_size": 10,
"max_batch_timeout": 5
}
]
}
}
Implementing the Consumer
Edit lib/consumer.rb to implement the message processing logic:
class Consumer < Uzumibi::Consumer
# @rbs message: Uzumibi::Message
def on_receive(message)
debug_console("[Consumer] Received message: id=#{message.id}, body=#{message.body}, attempts=#{message.attempts}")
# Process the message
body = message.body
debug_console("[Consumer] Processing: #{body}")
# Acknowledge after successful processing
if message.attempts > 3
# Give up and ack after more than 3 retries
debug_console("[Consumer] Giving up after #{message.attempts} attempts, acknowledging message #{message.id}")
message.ack!
else
# Normal processing
begin
process_message(body)
debug_console("[Consumer] Successfully processed message #{message.id}")
message.ack!
rescue => e
debug_console("[Consumer] Error processing message: retrying in 5 seconds")
message.retry(delay_seconds: 5)
end
end
end
def process_message(body)
# Actual message processing logic
debug_console("[Consumer] Message content: #{body}")
# Write specific processing here
# e.g., calling external APIs, saving data, etc.
end
end
$CONSUMER = Consumer.new
Code Walkthrough
Inheriting Uzumibi::Consumer
class Consumer < Uzumibi::Consumer
def on_receive(message)
# ...
end
end
Inherit from Uzumibi::Consumer and override the on_receive method. This method is called each time a message is received from the queue.
Message Attributes
The message object (Uzumibi::Message) passed to on_receive provides the following information:
message.id # Message ID (string)
message.body # Message body (string)
message.attempts # Delivery attempt count (integer)
message.timestamp # Send timestamp (ISO 8601 format string)
Acknowledgment (ack!)
message.ack!
Call ack! on a message once processing is complete. Messages that have been acknowledged are removed from the queue.
Retry
message.retry(delay_seconds: 5)
If processing fails, call retry to redeliver the message. Specify the delay time until redelivery in seconds with delay_seconds. The next time on_receive is called, message.attempts will be incremented.
Global Variable $CONSUMER
$CONSUMER = Consumer.new
Assign the consumer instance to the global variable $CONSUMER. This is referenced from the Rust code on the Wasm side, so it must always be set.
Deploying for Verification
Note: With the current Wrangler, Queue communication across multiple projects cannot be verified in the localhost development environment.
Deploy queue-consumer for verification.
First, perform the build:
pnpm install
pnpm run dev
# The HTTP part is empty, so it starts but behavior can't be verified.
# This is just to build the Wasm, so stop it afterwards.
Verifying Operation
Testing
To check the received logs, display logs in the terminal with the following command:
Terminal (queue-consumer):
$ cd queue-consumer
$ npx wrangler tail
⛅️ wrangler 4.73.0
───────────────────
Successfully created tail, expires at 2026-03-14T19:19:39Z
In a separate terminal, issue the following curl command to send a message:
curl -X POST -d "Test message from publisher" \
http://queue-publisher.<ID>.workers.dev/api/send
{"message":"Test message from publisher","status":"accepted"}
Message processing logs will appear in the queue-consumer console:
Queue my-app-queue (1 message) - Ok @ 2026/3/14 22:22:05
(log) [debug]: [Consumer] Received message: id=25f4ef4ca8b2fdb7055cc5b9XXXXXXXX, body=Test message from publisher, attempts=1
(log) [debug]: [Consumer] Processing: Test message from publisher
(log) [debug]: [Consumer] Message content: Test message from publisher
(log) [debug]: [Consumer] Successfully processed message 25f4ef4ca8b2fdb7055cc5b9XXXXXXXX
Processing status can also be checked from the Cloudflare dashboard under "Workers & Pages" > target Worker > "Logs".
Chapter Summary
Queues enable easy asynchronous processing with Cloudflare Workers + Uzumibi.
When using Queues, the architecture is somewhat special. Please note that with Uzumibi, two Workers are required.
Appendix: Uzumibi Reference Information
This chapter covers supplementary information that was not included in the main chapters.
Supported Platforms
Uzumibi supports multiple edge computing platforms. When creating a project with the uzumibi new command, you select the target platform using the --template option.
Platform List
| Platform | Template Name | Status | WASM Target |
|---|---|---|---|
| Cloudflare Workers | cloudflare | Beta | wasm32-unknown-unknown |
| Fastly Compute@Edge | fastly | Experimental | wasm32-wasip1 |
| Spin (Fermyon Cloud) | spin | Experimental | wasm32-wasip1 |
| Google Cloud Run | cloudrun | Experimental | Native (container) |
| Service Worker | serviceworker | Experimental | wasm32-unknown-unknown |
| Web Worker | webworker | Experimental | wasm32-unknown-unknown |
Cloudflare Workers
Cloudflare Workers is a platform for running serverless code on Cloudflare's global network. Uzumibi has the most advanced development for this platform, supporting the following features:
- Basic HTTP request/response processing
- Static asset serving (
public/directory) - External HTTP requests (
Uzumibi::Fetch) - Data persistence with Durable Objects (
Uzumibi::KV) - Asynchronous messaging with Cloudflare Queues (
Uzumibi::Queue)
Development uses Node.js (pnpm), the Wrangler CLI, and the Rust toolchain.
Fastly Compute@Edge
Fastly Compute@Edge is a platform for running WASM applications on Fastly's CDN edge nodes. It uses glue code written in Rust for request processing.
Development uses the Fastly CLI and the Rust toolchain.
Spin (Fermyon Cloud)
Spin is a WebAssembly microservice framework developed by Fermyon. It can be deployed to Fermyon Cloud and run as a serverless application.
Development uses the Spin CLI and the Rust toolchain.
Google Cloud Run (Experimental)
Google Cloud Run is a container-based serverless platform. In Uzumibi, the application is packaged as an HTTP server using Tokio + Hyper in a container, ready to run on Cloud Run.
Unlike other platforms, it is built as a native binary rather than Wasm. A Dockerfile is automatically included, so you can build a container from it.
Since the project is created in a form that can also run on localhost, development is possible as long as Docker is installed. Having the Rust toolchain available is also helpful.
Service Worker / Web Worker (Experimental)
These are experimental templates for running Uzumibi applications on the client side using the browser's Service Worker API or Web Worker API.
The Rust toolchain is required for creating the Wasm.
Disclaimer
Note: The names and trademarks of each platform and software belong to their respective operating companies. This book cites these intellectual properties for introductory purposes.
Current Limitations
Multi-File Application Code
Currently, Uzumibi requires that Ruby application code be written in a single file (lib/app.rb or lib/consumer.rb).
In typical Ruby development, it's common to split code across multiple files using require or require_relative for modularization. However, in Uzumibi, these file-loading features are not available due to mruby/edge's limitations. For now, the workaround is to write all code in a single file or concatenate files using a build script.
Multi-file support is a feature that will be prioritized in future Uzumibi development.
Language Feature Limitations of mruby/edge
Since mruby/edge implements a subset of mruby, it has some limitations compared to CRuby (standard Ruby) or the full mruby:
- Some standard libraries: Libraries that depend on OS resources such as
File,IO, andSocketare not available in the WebAssembly environment. - Regular expressions: Regular expressions (
Regexp) currently have only partial support. require/load: As mentioned above, loading external files is not supported.- Threads / Fiber: Concurrency features are not available due to WebAssembly environment constraints.
Additionally, the Ruby features available may vary by platform in the future. We plan to document these as much as possible.
Feature Differences Between Platforms
Note: This section is updated periodically. Last updated: March 14, 2026.
While Uzumibi supports multiple platforms, external service integration features differ by platform:
| Feature | Cloudflare | Fastly | Spin | Cloud Run |
|---|---|---|---|---|
| Basic HTTP processing | o | o | o | o |
| External HTTP requests (Fetch) | o | - | - | - |
| Key-Value store | o (Durable Object) | - | - | - |
| Message queue | o (Queues) | - | - | - |
| Static asset serving | o | - | - | - |
Currently, Cloudflare Workers supports the most features. Support for other platforms is expected to expand progressively.
References
Uzumibi
- Uzumibi Official Documentation: https://mrubyedge.github.io/uzumibi/
- Uzumibi Repository (GitHub): https://github.com/mrubyedge/uzumibi
- uzumibi-cli (crates.io): https://crates.io/crates/uzumibi-cli
- uzumibi-gem (crates.io): https://crates.io/crates/uzumibi-gem
mruby/edge
- mruby/edge Repository (GitHub): https://github.com/mrubyedge/mrubyedge
- mrubyedge (crates.io): https://crates.io/crates/mrubyedge
- mec - mruby/edge compiler (crates.io): https://crates.io/crates/mec
mruby
- mruby Official Site: https://mruby.org/
- mruby GitHub: https://github.com/mruby/mruby
Cloudflare Workers
- Cloudflare Workers Documentation: https://developers.cloudflare.com/workers/
- Wrangler CLI: https://developers.cloudflare.com/workers/wrangler/
- Cloudflare Durable Objects: https://developers.cloudflare.com/durable-objects/
- Cloudflare Queues: https://developers.cloudflare.com/queues/
- Cloudflare Workers Static Assets: https://developers.cloudflare.com/workers/static-assets/
WebAssembly
- WebAssembly Official Site: https://webassembly.org/
- Rust and WebAssembly: https://rustwasm.github.io/docs/book/
Rust
- The Rust Programming Language: https://www.rust-lang.org/
- rustup (Rust Installer): https://rustup.rs/
- The Rust Programming Language (Book): https://doc.rust-lang.org/book/