Rust(wasm): On-Premise workerd-runtime(Cloudflare-style)
Hi everybody!
Here-is a simple, logical outline in text-format(a data flow) that explains exactly how an HTTP-request travels from the outside into [y]our Rust-code(index.wasm) and back, using the `workerd`-architecture:
[ User / Browser ]
│
│ (1) Sends HTTP Request (e.g., GET /api/data)
▼
┌────────────────────────────────────────────────────────────┐
│ YOUR SERVER (On-Premises) │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ workerd │ │
│ │ (Runtime started with config.capnp configuration) │ │
│ │ │ │
│ │ Receives the Request and forwards it to: │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ V8 Isolate-Sandbox │ │ │
│ │ │ │ │ │
│ │ │ (2) index.js(JavaScript Glue-Code) │ │ │
│ │ │ │ Maps JS objects from V8 │ │ │
│ │ │ │ (Request, Headers) to types │ │ │
│ │ │ │ compatible with WebAssembly. │ │ │
│ │ │ ▼ │ │ │
│ │ │ (3) index.wasm(Your Rust-Code) │ │ │
│ │ │ │ │ │ │
│ │ │ │ Executes logic from workers-rs. │ │ │
│ │ │ │ Processes data rapidly. │ │ │
│ │ │ ▼ │ │ │
│ │ │ (4) Returns a binary-Response │ │ │
│ │ │ │ │ │
│ │ └───┼────────────────────────────────────────┘ │ │
│ │ │ │ │
│ │ ▼ (5) Converts the binary into an HTTP-Response │ │
│ └──────┼───────────────────────────────────────────────┘ │
│ │ │
└─────────┼──────────────────────────────────────────────────┘
│
▼ (6) Sends the Response back(e.g., 200 OK, JSON)
[ User / Browser ]You can run Cloudflare(CF) Workers(using the workers-rs SDK, to write your logic, over your data, in your Rust wasm-code) locally or on-premises(on-prem) by using workerd — the official, open-source, V8-based runtime created-by Cloudflare(CF). Since workers-rs compiles code natively into WebAssembly(wasm32), it does not rely on Cloudflare’s cloud infrastructure to execute.
Below, you will find how-to configure a local-execution environment on your own-machine or within a local/on-premise infrastructure):
1. Local development and testing(Wrangler & Miniflare)
The simplest-way to run code locally during development is by using the official Cloudflare-CLI, called Wrangler. It launches a local-instance of `workerd` in the background(via Miniflare):
1-a). Scaffolding: Generate the Rust-project
cargo generate cloudflare/workers-rs1-b). Local execution: Launch the local-server, which will listen-on localhost:8787(by default)
npx wrangler devNote: As of recent versions of the Cloudflare Workers docs, the `wrangler dev`- command runs the code entirely-locally on [y]our machine by-default (without routing traffic through Cloudflare-servers), using the native `workerd`- runtime.
2. On-premises hosting in-production(by using directly the native `workerd` as runtime)
If you wish-to completely-eliminate your dependency-on the Cloudflare-platform and run your Rust-compiled worker on [y]our own on-premises servers in a production-environment, you must-use the `workerd` binary directly.
2-a) Compiling the project: Generate the .wasm binary using the Rust-toolchain
# Using worker-build from the workers-rs ecosystem
npx worker-build --releaseThis will generate a WebAssembly file and optionally a binding JavaScript “glue” file (generated-by wasm-bindgen).
2-b) Configuring workerd: Create a configuration-file named config.capnp (which uses the Cap’n Proto protocol) to define how workerd will route requests to [y]our WASM file.
2-c) Running the server: Execute the runtime on your local server
workerd serve config.capnpImportant Technical-Considerations:
- Async/Threading Limitations: The `workers-rs` SDK is designed-for the cooperative, single-threaded architecture specific-to V8. You cannot use standard Rust async runtimes that require multi-threading (such as the default `#[tokio::main]` macro). Instead, you must use the `#[event(fetch)]` macro provided by the `worker` crate.
• Data-Storage(KV, D1, Durable-Objects): If you are running entirely on-prem, cloud-services such as Cloudflare KV or the D1 database will be simulated locally(using SQLite as the underlying local-storage, managed automatically by the runtime).
Remark:
- The
workerdit is not a runtime for standard native binaries(such-as .exe files on Windows or ELF files on Linux). - The
workerdis a runtime designed specifically-for JavaScript(JS), TypeScript(TS), and WebAssembly(WASM).
Here is how it actually-works in the context-of your Rust code:
Get Ion’s stories in your inbox
Join Medium for free to get updates from this writer.
1. What does `workerd` actually execute?
When you use `workers-rs`, your Rust-written code is not compiled into a native binary for the server’s processor(x86_64 or ARM). Instead, it is compiled into WebAssembly(.wasm).
• Based on V8: `workerd` is built-upon Google’s V8-engine (the same engine used in Google Chrome and Node.js).
• Isolates: Rather-than launching a full operating-system(OS) process for each application, it utilizes a technology-called “V8 Isolates”. This technology(“V8 Isolates”) allows it(`workerd`) to run thousands-of applications simultaneously, with extremely-low memory- consumption and near-instant startup(zero cold start).
2. How-does Rust run within `workerd`(as runtime)?
The process-by which Rust code ends up running in `workerd` is as follows:
2-a). The Rust code is translated-by the compiler into WebAssembly bytecode(target: `wasm32`).
2-b). A small JavaScript file(automatically generated-by `wasm-bindgen`) acts-as a “bridge”(glue-code) between `workerd` and the WebAssembly- module.
2-c). `workerd` loads this JavaScript-script, which, in-turn, instantiates and executes the WebAssembly-code compiled-from Rust(rs2wasm).
Difference compared-to a native-binary runtime:
If you need-to run a native Rust binary(compiled-directly for the operating system/OS), `workerd` is not the right tool. For native, on-premise binaries, standard-alternatives(as/for runtime) include:
- A minimal Docker container.
- A system-service(such-as `systemd` on Linux).
- Runtimes specific to micro-VMs (such-as AWS’s Firecracker).
The workerd is ideal only if you wish to maintain the exact same behavior, APIs, and performance offered-by the Cloudflare Workers platform, but on your own infrastructure.
After compiling a workers-rs project using the official command `npx worker-build — release` (which internally uses `wasm-pack` and `wasm-bindgen`), the final production artifacts are generated in a folder named `build/` (or `dist/`, depending on the configuration in `wrangler.toml`).
The exact-structure of the folder generated for production looks-like this:
📂 Structure-of the resulting files(build/):
my-worker-project/
├── build/
│ ├── index.js # The "glue" JavaScript file (the connecting bridge)
│ └── index.wasm # The Rust code compiled into WebAssembly
├── src/ # The Rust source code (.rs)
├── Cargo.toml # The Rust project configuration
└── wrangler.toml # The Cloudflare / workerd configuration🔍 What-does each important-file contain?
1. 📄 index.js (JavaScript Glue-Code)
This is the main file that workerd will read. Since the V8-engine doesn’t natively-know how-to map complex Rust data-types(like strings, structs, or HTTP-requests) to JavaScript types, this file does the translation.
• It imports the .wasm module.
• Contains the “internal mechanics”-functions generated-by wasm-bindgen.
• Exposes the fetch event listener function that workerd calls when it(workerd) receives an HTTP-request, routing-it further-to the Rust-code.
2. 📄 index.wasm(WebAssembly binary-module)
This is the “engine” of [y]our application — all the Rust-code you wrote, along-with the dependencies-in Cargo.toml, optimized and compiled into a compact binary bytecode format.
• It(index.wasm) is a binary, non-text file(if you open it/index.wasm in an editor, you will-see hexadecimal characters).
• It(index.wasm) is completely-isolated, running in the secure WebAssembly sandbox inside-the workerd.
⚙️ How-does wrangler.toml or workerd see them(index.js and index.wasm)?
In-order for these two files to work-together at/@ runtime, they are linked in the configuration file(wrangler.toml). In wrangler.toml, the build-section usually looks-like this:
name = "my-rust-worker"
main = "build/index.js" # Tells workerd to run the JS file first
[build]
command = "npx worker-build --release"When you start npx wrangler dev or run workerd serve, the runtime loads index.js, which-loads the index.wasm binary into memory, and from that-moment the Rust-code is ready-to respond-to network-requests.
Enjoy!
That is all! Bye…Bye!






