At QCon SF 2025, Spencer Judge, SDK Team Lead at Temporal, presented a case for using a shared Rust core to build and maintain robust multi-language SDKs efficiently.
The talk detailed Temporal’s journey toward a highly efficient, unified architecture centered on a shared core written in Rust, which Judge framed as a safer, more portable, and ultimately cheaper alternative to traditional C-based shared logic. Temporals’ strategy addresses the high cost and complexity senior developers face in maintaining consistent business logic across an expanding matrix of SDKs (including Python, Go, TypeScript, Java, and Ruby).
The core problem, as Judge outlined, is that developers today expect to be met in their preferred language. Rewriting complex, client-side logic, such as durable execution state machines, for every language is costly, redundant, and error-prone. Rust was chosen over C for this foundational role due to its exceptional safety, speed, portability, and strong C/C++ Foreign Function Interface (FFI).
Temporal’s architecture is layered to isolate complexity and maximize efficiency:
- Shared Core (Rust): Contains the complex, centralized, non-redundant business logic.
- Rust Bridge: Thin, language-specific layers that facilitate FFI, handling the communication primitives.
- SDK (Host Language): The minimal outer layer that exposes a high-quality, idiomatic API to the end user.
This approach results in dramatically fewer bugs by reducing code redundancy and enables a small team to scale coverage efficiently.
The technical complexity is concentrated in the FFI bridge. Judge detailed the use of specialized crates to simplify binding the Rust core to various language runtimes: PyO3 for Python, Neon for Node.js/TypeScript, and Magnus for Ruby.
Successfully managing the cross-boundary communication requires strict adherence to technical best practices:
- Type Management: While Interface Description Languages (IDLs), like Protobuf, are used for type code generation, a critical principle is to keep the bridge layer slim, relying on simple, generic types (e.g., primitives or buffers) for data transfer.
- Asynchronous Handling: This is particularly challenging, requiring specialized strategies (often involving callbacks or internal queueing) to connect Rust’s async model to host-language constructs and safely navigate concurrency challenges such as the Global Interpreter Lock (GIL).
- Memory Management: Judge emphasized a non-negotiable rule: “Allocation and Deallocation must happen in the same environment.” This prevents memory leaks and corruption that commonly plague traditional C-based FFI architectures.
Judge concluded with a look at future improvements and a core philosophical takeaway for senior engineers:
Temporal is actively addressing the “Distribution Dilemma”, the enormous challenge of packaging and shipping platform-specific native binaries (lib*.so or *.dll files) across diverse ecosystems. The most promising path forward is compiling the Rust core to WebAssembly (Wasm), which would eliminate many cross-platform native extension pain points and greatly improve portability.
On the performance front, Judge advised developers to benchmark assumptions, as optimized serialization can sometimes outperform direct object creation. The team is also investigating non-serializing IDLs such as FlatBuffers and Cap’n Proto for further speed gains.
Ultimately, Judge stressed that the primary focus must remain on the user. Engineers must take the time to ensure the final SDK delivers a “nice, clean, magic experience,” rather than a “crappy auto-generated” one, by designing generic extension points early on and enabling the host language to easily inject custom behavior into vital functions such as logging and metrics. He stated that by adopting this Rust-based shared core, software leaders can efficiently expand their language coverage and deliver superior quality to their users, thereby reducing complexity and technical debt across the organization.
