NVIDIA's CUDA Rust Brings Compile-Time Kernel Safety via Two Crates
In this article
NVIDIA's NVlabs has released two open-source Rust crates that make Rust a first-class language for writing GPU kernels: cuda-oxide for the SIMT programming model and cutile-rs for the newer Tile model. Rust code could already orchestrate CUDA kernel launches, but the kernel body itself had to be authored elsewhere. Both crates use Rust's ownership and borrow-checking rules to reject buffer aliasing at compile time — before any GPU work executes — which is the concrete safety advance worth understanding here.
For ML infrastructure engineers writing custom operators or inference kernels, the stakes are direct. The class of bugs these crates block — a kernel reading and writing the same buffer simultaneously — has historically been a runtime problem, invisible until a silent memory corruption surfaces in a production inference run. As software-layer extraction increasingly outpaces hardware acquisition at the systems frontier, compile-time kernel safety is one of the few mechanisms that directly reduces the debugging surface of that layer.
Two Compilation Pipelines, Two Safety Models
The SIMT track, cuda-oxide, is a custom rustc codegen backend. Functions tagged #[kernel] inside a #[cuda_module] block pass through Rust MIR, then to the community Pliron IR framework (where NVIDIA has added GPU dialects), then to LLVM IR, and finally to PTX. The host binary embeds that device bundle and launches it through a checked contract.
The Tile track, cutile-rs, works differently: a #[cutile::module] proc macro captures the kernel AST and embeds it directly in the host binary, deferring actual compilation to a JIT step through CUDA Tile IR on first launch. The resulting GPU cubin is cached per tile-width specialisation — a new value of the const B triggers a new build.
The safety argument differs between tracks. In cuda-oxide, the output buffer is typed as DisjointSlice rather than &mut [f32]. Because a plain mutable slice would require every thread to hold the same mutable borrow simultaneously — which Rust refuses — the type system forces the exclusive-access invariant. c.get_mut(idx) returns Option, converting out-of-bounds access into a handled branch. A #[launch_contract] attribute declares the block shape, and the generated prepare_vecadd method validates the launch configuration before the safe launch proceeds. A write/read alias on the same buffer produces error[E0502]: cannot borrow c_dev as mutable because it is also borrowed as immutable.
On the Tile side, cutile-rs's .partition([128]) call does three things simultaneously: it gives each tile exclusive ownership of its 128-element chunk, fixes the grid at 1,024 ÷ 128 = 8 tiles, and supplies the const tile width B. The generated launcher takes ownership of all tensors and returns them when the GPU finishes. Nothing executes until .sync_on(&stream). An aliasing attempt produces error[E0382]: use of moved value: z, because the launcher consumed ownership of z when it was partitioned. NVIDIA describes this ownership-follows-tensor-across-launch-boundary guarantee as the stronger of the two — Tile exposes no shared memory or thread indexing to misuse. SIMT retains that lower-level control, but shared memory in cuda-oxide currently requires unsafe.
Requirements and Current Deployability
| Requirement | cuda-oxide (SIMT) | cutile-rs (Tile) |
|---|---|---|
| Status | Early alpha | On crates.io; used in Grout and mistral.rs |
| Rust toolchain | Pinned nightly-2026-04-03 | Stable 1.89 or newer |
| CUDA Toolkit | 12.x or newer | 13.3 |
| GPU | Compute capability 8.0+ | Compute capability 8.0+ |
| OS | Linux | Linux |
| Extra dependencies | clang + libclang; optional system LLVM | None |
| Install | cargo +nightly install cargo-oxide (git) | cargo add cutile |
| Compile model | Ahead-of-time to PTX | JIT via CUDA Tile IR |
| Shared memory | Available, requires unsafe today | Managed by compiler |
cutile-rs is the operationally closer option: it installs from crates.io with a single cargo add, runs on stable Rust 1.89+, requires CUDA 13.3, and is already embedded in Hugging Face's Grout inference engine and in mistral.rs. cuda-oxide requires the pinned nightly toolchain, CUDA 12.x or newer, clang with libclang, and a git-sourced install. Its cargo oxide doctor subcommand validates the environment; cargo oxide new scaffolds a vector-addition project with host and device code in a single file. Neither project has been confirmed production-ready by NVIDIA.
Where This Fits
The GPU kernel was the remaining gap in an otherwise Rust-native NVIDIA stack: the Nova Linux driver is written in Rust, NVIDIA Dynamo has a Rust core, and NVTX ships Rust bindings. Planned inter-language interop will prevent Rust kernel authorship from locking developers out of C++ or Python kernel code in the same project. The two tracks map directly to the two models CUDA C++ and Python already support — SIMT for explicit thread and memory control, Tile for higher-level data-parallel description — so no third programming model is introduced.
For teams primarily concerned with safe tensor arithmetic at inference time, cutile-rs on stable Rust is evaluable today. For those who need explicit warp-level control, cuda-oxide demands a locked toolchain but offers a compile-time safety boundary that C++ CUDA never provided.
Related Reading
NVIDIA's Switchyard Routes LLM Traffic Between OpenAI and Anthropic APIs
NVIDIA open-sources Switchyard, an Apache 2.0 Rust proxy that translates and routes LLM traffic across OpenAI and Anthropic wire formats, including streams.
Lily Beats MLX-LM 1.35x on Decode: Perplexity's Rust+Metal Engine for Apple Silicon
Perplexity open-sources Lily, a Rust+Metal inference engine for Qwen3.6-35B-A3B that averages 1.23× prefill and 1.35× decode over MLX-LM on an M5 Max.
NVIDIA Earth2Studio: Custom Batched Ensemble Forecasting Pipeline
Build a full ensemble weather pipeline in Earth2Studio using low-level iterators, custom diagnostics, Zarr I/O, and fair CRPS verification — all in one Colab session.