# First-Class Emscripten Support for Rust on Cloudflare Workers: A Deep Dive
## Breaking New Ground for Rust and WebAssembly on the Edge
Cloudflare has unveiled the first public experimental preview of a transformative capability: native Rust code—including Tokio-based applications—can now run directly on Workers without compromise. At the heart of this milestone is full first-class support for the Emscripten wasm32-unknown-emscripten compiler target within the wasm-bindgen open source toolchain and Cloudflare’s Rust Workers platform.
## Understanding the Core Technology
**wasm-bindgen** is the open source toolchain that powers Rust-based WebAssembly applications on Cloudflare’s V8-based Workers Runtime. For over a year, the wasm-bindgen maintainers—led by engineers at Google’s Portable Toolchains and Wasm Tools teams, in collaboration with Cloudflare—worked toward enabling the Emscripten target within this toolchain. This effort has opened up entirely new workflow possibilities for running native wasm-bindgen Rust applications across the web, Node.js environments, and Cloudflare’s global Workers platform.
**Emscripten** itself is a widely-used open-source WebAssembly compiler toolchain originally developed by Mozilla and now maintained by Google engineers. It enables native code to run and bridge with the web platform by virtualizing essential platform features—timers, file system operations, sockets, and other native capabilities—into JavaScript-compatible equivalents.
## Why This Matters for Compatibility
In internal testing, the team observed significantly improved library compatibility for Rust Workers. By leveraging Emscripten’s Node.js compilation flags, Cloudflare Workers is able to fully virtualize native platform features on top of its existing Node.js APIs. Since Workers already supports both Web Platform APIs and Node.js compatibility, the Emscripten integration slots naturally into the existing infrastructure.
The addition of Tokio support means that Rust code built on Tokio’s async runtime ecosystem can now be fully integrated into JavaScript-based host environments using this Emscripten target—a long-sought goal for the Rust and WebAssembly community.
## A Seamless Interoperability Breakthrough
One of the most significant technical achievements was resolving the fundamental conflict between wasm-bindgen and Emscripten. Both tools historically assumed they would be in sole charge of loading and interacting with JavaScript and generating the final output—creating an impossible choice for projects needing both toolchains.
The solution involved crafting a cooperative workflow: Emscripten continues to drive the build process, load the WebAssembly module, and produce companion JavaScript, while wasm-bindgen generates a compact, portable version of its JavaScript bindings that can be directly included in Emscripten’s library system. The result is seamless interoperability under the new `-sWASM_BINDGEN` configuration flag, which enables:
– C++ Emscripten code to be built against static wasm-bindgen Rust code, fully supporting both the wasm-bindgen bindings layer and the Emscripten bindings layer simultaneously.
– Rust applications using wasm-bindgen to be built for the Emscripten target, fully supporting Emscripten’s bindings layer alongside wasm-bindgen’s.
## Rust Library Ecosystem Support
With Emscripten target support landed in wasm-bindgen, early prototypes demonstrated impressive results on Cloudflare Workers. Many libraries worked immediately out of the box, including low-level systems libraries, since Emscripten already recognizes `target_family = unix` in Rust.
Certain low-level libraries—such as `libc`, `socket2`, and `Mio`—required targeted patches to add Emscripten to their existing platform gates, typically involving explicit `target_os = “emscripten”` entries alongside existing WebAssembly platform gates. These patches proved mostly trivial, and library maintainers were highly receptive to the contributions.
## Tokio Integration: Two Complementary Approaches
Tokio presented a unique challenge. Cloudflare Workers operate on a single-threaded model within a JavaScript event loop, whereas Tokio’s async runtime is designed around threaded parking semantics. A blocking operation like a pending socket read cannot simply block the shared JavaScript event loop.
Developers tackled this through two complementary strategies:
### Approach 1: WebAssembly JavaScript Promise Integration (JSPI)
JSPI maps directly onto Tokio’s existing parking semantics by allowing a blocking WebAssembly call to suspend the Wasm stack during a synchronous operation and return control to the JavaScript event loop—functionally equivalent to a park operation. When a new WebAssembly call is made while a previous one is suspended, JSPI handles it gracefully by supporting multiple suspended stacks simultaneously.
However, Rust itself is unaware that its stack is being swapped out. Tokio’s runtime context is tracked through thread-local storage, and since a JSPI stack switch is not a thread switch, both the suspended and new stacks share the same thread-local runtime context. Solving this required carefully splitting context between JSPI context switches—effectively implementing cooperative time-multiplexed threading where each suspended stack carries its own runtime context.
### Approach 2: LocalEventLoop Runtime for Tokio
The second approach introduces a full event loop integration designed to work across native applications (including Windows and macOS) and WebAssembly embeddings in JavaScript hosts. The design splits Tokio’s traditional loop into two parts: an explicit `drive()` operation that runs one batch of ready tasks and returns, and a wake mechanism that replaces parking with a notification to the host event loop.
Under this model, the Tokio runtime uses a standard `std::task::Waker` owned by the host to signal when the runtime itself needs driving. This means every operation that would have unparked a native thread—spawn calls, task wakes from other threads, socket readiness, timer expirations—all simply wake the host instead. The `LocalEventLoop` design ensures the host event loop is never blocked, allowing it to interleave its own work with Tokio’s one batch at a time.
## Sockets and Epoll Support on Emscripten
Supporting full networking required bridging Emscripten’s virtualization layer with Cloudflare’s own sockets API. The team realized that the `node:net` API already available in Workers’ Node.js compatibility layer could serve as this bridge.
The solution involved contributing over forty pull requests to Emscripten, resulting in the `-sNODERAWSOCKETS` compilation option. This enables support for epoll, TCP, UDP, and Unix sockets for Emscripten applications in Node.js—and on Cloudflare Workers itself, since Workers implements the same `node:net` API.
Under JSPI, Emscripten’s `epoll_wait()` suspends the stack until readiness, letting Tokio’s I/O driver function as it would natively. For `LocalEventLoop`, readiness reaches the Waker through a JavaScript callback, with a new `emscripten_epoll_add_listener` API associating callbacks on an epoll’s ready events for collection during the next `drive()` call.
## Proof of Concept: A Minecraft Server on Workers
To validate the entire stack, developers successfully deployed a Rust-native Minecraft server—called **Pumpkin**—inside a Durable Object with TCP ingress, using real TCP sockets via Tokio.
Pumpkin is a Minecraft server written in Rust and built on Tokio, designed for multi-core machines. Its architecture separates concerns across multiple threads: world generation runs on a dedicated thread pool, while the game tick loop and chunk scheduler each operate on their own operating system threads. Running inside a Durable Object—which provides exactly one thread—required converting those threads into cooperative tasks on the event loop. The Tokio integration enabled the tick loop and chunk scheduler to become async tasks, with each Rayon job becoming a Tokio task. World generation runs on the event loop itself, taking one turn per chunk and interleaving with network I/O and game ticks.
Persistence was handled through the `node:fs` compatibility layer enabled by Emscripten’s `-sNODERAWFS` option. A custom `worker-fs-mount` library mounts a `node:fs`-compatible file system backed by the Durable Object’s SQLite storage, so every file Pumpkin saves becomes a database row committed with the object’s transaction. Networking required no changes to Pumpkin itself—each player connection arrives through Workers TCP ingress and is dispatched into the Durable Object via `handleAsNodeConnection()` from `cloudflare:node`, which creates a `net.Server` listening inside the object. Emscripten’s `-sNODERAWSOCKETS` backend implements `TcpListener` on top of `net.Server`, allowing the server to accept players exactly as it would on Linux.
## How to Get Started
The complete patchsets and workflows are available today for experimental use. Developers can explore example applications demonstrating Rust-based WebAssembly applications running natively on the Workers platform with full Emscripten support. Contributions and feedback are welcomed through GitHub and community channels dedicated to Rust on Workers.
## Frequently Asked Questions
**What is wasm-bindgen and how does it relate to this announcement?**
wasm-bindgen is the open source toolchain that generates JavaScript bindings for Rust-compiled WebAssembly modules, enabling Rust code to interact seamlessly with JavaScript environments. This announcement extends wasm-bindgen to support the Emscripten Rust compiler target, allowing Rust applications built with wasm-bindgen to target environments where Emscripten is used.
**What is Emscripten and why is it important for WebAssembly?**
Emscripten is an open-source WebAssembly compiler toolchain that bridges native code with the web platform. It virtualizes platform features like timers, file systems, and sockets, translating them into JavaScript-compatible APIs. Supporting Emscripten as a target means Rust applications can leverage this bridging capability within Cloudflare Workers.
**How does Tokio work in a single-threaded JavaScript event loop?**
Tokio traditionally relies on threaded parking semantics, which conflicts with single-threaded event loops. Two solutions are being developed: WebAssembly JavaScript Promise Integration (JSPI), which suspends WebAssembly stacks during waits, and a new LocalEventLoop runtime design that replaces parking with host-driven wake notifications, allowing Tokio tasks to be driven cooperatively by the host event loop.
**Can I run any Rust application on Workers with this new target?**
Many Rust applications and libraries work out of the box thanks to Emscripten’s existing support for Unix-targeted Rust code. However, applications relying on highly specialized native APIs may still require adjustments. The team has demonstrated success with a full Minecraft server, and compatibility continues to expand.
**What are Durable Objects and why were they used for the Minecraft server?**
Durable Objects are Cloudflare’s stateful compute primitive that provides exclusive single-threaded execution with built-in persistence. They were used to host the Minecraft server because they offer a persistent storage backend and TCP ingress capabilities, making them ideal for running stateful networked applications at the edge.
**Is this feature available for production use?**
This is currently an experimental preview. The patchsets and example workflows are available for testing and experimentation, but the feature is not yet recommended for production deployments.
**How can I contribute or provide feedback?**
Developers are encouraged to contribute through the wasm-bindgen GitHub repository and join the #rust-on-workers channel on Cloudflare’s Discord server to share feedback and collaborate with the teams working on this feature.
## Conclusion
The introduction of first-class Emscripten support for Rust on Cloudflare Workers represents a significant leap forward for the Rust and WebAssembly ecosystem. By bridging the gap between wasm-bindgen and Emscripten, enabling full Tokio integration, and supporting native networking through Emscripten’s Node.js socket bridge, developers can now bring sophisticated Rust applications—including async networked services—to the edge with minimal friction. The successful deployment of a full Minecraft server demonstrates that the level of native compatibility achieved is not theoretical but practical and production-viable. As these experimental patchsets continue to mature and receive upstream integration, the possibilities for Rust-based edge computing will only continue to expand.
Thank you for reading



