Use MainSDK from Rust
Add the native mainsdk crate to a Rust service, store data and files as one owner, and return problem details from axum.
Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.
Stability The promise an interface ships with.
- Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
- Beta Usable in production; may change before it becomes stable.
- Experimental May change or go away; needs an explicit opt-in in main.yaml.
You will add the mainsdk crate, run it on its local drivers, and wire an axum route. It takes about 15 minutes. The crate is native Rust: it shares no code with the TypeScript SDK, only main.yaml, the error codes and the wire formats.
You need
- Rust 1.85 or later and a
main.yamlwithschema: 1(npx mainsdk initwrites one). - The crate is pre-release and not on crates.io. Use a path or git dependency from the MainSDK repository until it is published.
1. Add the crate
[dependencies]
mainsdk = { path = "../mainsdk/packages/rust/mainsdk", features = ["kv", "files", "axum"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }Each interface sits behind a feature of the same name. config and log are on by default.
2. Call an interface
Calls are builders you .await directly. A tenant-scoped call needs a tenant, which travels in a task-local Context.
use mainsdk::prelude::*;
#[tokio::main]
async fn main() -> mainsdk::Result<()> {
let app = App::load().await?;
Context::new().tenant("tnt_a").user("u1").scope(async {
app.kv().set("cart", 3).await?;
let file = app.files().upload(b"hello".to_vec()).owner("u1").await?;
app.log().info("uploaded").field("file", &file.id).await;
Ok::<_, MainError>(())
}).await
}Spawn with mainsdk::spawn, not tokio::spawn, so the context follows the task. A call that needs a tenant and has none fails with MAIN-TENANT-0001.
3. Return problem details from axum
let router = axum::Router::new().route("/cart", handler).layer(app.layer());The layer reads traceparent, sets the context, and renders any MainError as application/problem+json with its code, fix and trace_id.
4. Cancel and time out
Drop the future to cancel a call and release what it held. To stop one on purpose, pass a token with .cancel(token); the call fails with MAIN-SDK-0001.
5. Check the project
npx mainsdk check runs clippy (MAIN-RUST-0001), cargo-audit (MAIN-RUST-0002) and cargo-deny (MAIN-RUST-0003) with the usual gates. A missing tool is a warning, MAIN-RUST-0004, never a pass. Run cargo test too.
Next
- Key-value store, Files and the other first-cut interface pages show a Rust tab.
- Rust agents load the
mainsdk-rustskill.
Was this page helpful?