Rust
For trusted, performance-critical Particles you can author in Rust. Instead
of one call per row, the server exchanges whole Arrow RecordBatches over the
Apache Arrow C Data Interface — one call per batch, with zero-copy of the
data (Arrow buffers are shared, not serialized). On a tight loop that is the
fastest tier.
The contract is the same as Python: your Rust function’s signature is the SQL signature, STRICT-null is honoured, and the same naming rules apply.
When to reach for Rust
Section titled “When to reach for Rust”- Hot paths only. Batch-at-a-time Arrow exchange plus native code makes this the fastest tier when a Particle is on a tight inner loop. For everything else, Python is simpler and quick to iterate on.
- Trusted code only. A compiled Rust Particle runs with the engine’s full OS authority (operator-vetted, digest-pinned). Untrusted / multi-tenant Particles are the domain of the (future) sandboxed WASM tier, not this one.
Author the function
Section titled “Author the function”You write only the function body; the SDK owns the Arrow FFI shim (the ABI
discovery symbols and the panic-guarded, batch entrypoint). The example crates
live at examples/particles/rust/:
/// domain_of(text) -> text — the domain part of an email.fn domain_of(email: &str) -> &str { email.rsplit('@').next().unwrap_or("")}The crate is a standalone cdylib:
[lib]name = "domain_of"crate-type = ["cdylib"]
[dependencies]particle-abi = { path = "…/crates/particle-abi" } # shared C-ABI structsarrow = { version = "53", features = ["ffi"] } # same Arrow major as the hostBuild the artifact
Section titled “Build the artifact”cd examples/particles/rust/domain_ofcargo build --release# -> target/release/libdomain_of.dylib (macOS)# target/release/libdomain_of.so (Linux)Run it
Section titled “Run it”Start a server built with the Rust tier, then load the built artifact the same way you load any Particle (Loading) — the tier is selected automatically from the artifact, so once it’s loaded you just call it from SQL:
cargo build --release --bin spanner --features spanner-exec/particles-rustparticledb start --no-auth --data-dir /tmp/pdb_rust --pg-addr 0.0.0.0:5432SELECT domain_of(email) FROM users; -- 'kyle@jepsen.io' -> 'jepsen.io'Parity with Python
Section titled “Parity with Python”The Rust tier honours the same contracts as the Python tier: STRICT-null (a
NULL argument yields NULL without invoking the body), immutable volatility by
default, deny-by-default capabilities, and the built-in
collision rule. The end-to-end regression
(crates/exec/tests/particles_rust_cdylib_regression.rs) builds each example,
loads it, and asserts the SQL result value — e.g. domain_of('kyle@jepsen.io')
returns jepsen.io.
Next steps
Section titled “Next steps”- Best Practices — when Rust is worth the compile step, and how to keep a Particle safe.
- Loading — get your Particles into a running server.
- Async Agents & Workflows — the async preview tier.