Rust
The Rust compile path is a managed runtime β you write an annotated handler and the platform compiles it to a native Linux binary (or a Wasm component) and runs it. The compiled artifact is small and starts fast. The platform owns the HTTP server, the listening port, and the readiness probe; you only write the handler.
Handler contract
Annotate a function named handler with #[ignite::main]:
#[ignite::main]
async fn handler(req: Request, ctx: Context) -> Result<impl IntoResponse>A synchronous fn handler(...) is also accepted. The #[ignite::main] macro provides the HTTP server, request decoding, and context wiring.
A minimal real handler (from code_sources/rust-hello/src/lib.rs):
use ignite::prelude::*;
use serde_json::json;
#[ignite::main]
async fn handler(req: Request, ctx: Context) -> Result<impl IntoResponse> {
let message: String = req
.field("message")
.unwrap_or_else(|_| "Hello from Rust!".to_string());
Ok(json!({
"message": message,
"execution_id": ctx.execution_id(),
"function_id": ctx.function_id(),
}))
}Context
Context exposes methods (not fields):
| Method | Returns / does |
|---|---|
ctx.execution_id() | &str β this invocationβs ID |
ctx.function_id() | &str β the app ID, in "org/func" form |
ctx.env() | environment access |
ctx.temp_store() | per-execution scratch store |
ctx.stream() | streaming response handle |
Input & output
The request body is parsed as JSON into Request. Read it with:
`req.field::<T>("key")`β a single typed field`req.body::<T>()`β the whole body deserialized intoTreq.raw()β the raw bytes- HTTP accessors:
req.method(),req.path(),req.query_param(),req.header()
Return any impl IntoResponse (for example `ignite::json!({...})`); it is serialized to JSON and returned as HTTP 200. An Err return or a panic yields HTTP 500 with a JSON body of the form `{error}`.
Dependencies
Declare crates in Cargo.toml at the archive root. The compiler auto-injects ignite, serde (with derive), serde_json, and tokio if they are absent, so you can omit them.
For the ignite dependency:
- In a standalone project, use
`ignite = "*"`β the compile pod swaps in the bundled SDK at build time. - The in-repo fixture instead uses
`ignite = { workspace = true }`.
Project layout
Ship an archive (zip / tar.gz) with Cargo.toml at the root. The #[ignite::main]-annotated handler lives where youβd expect Cargo to find it β conventionally src/lib.rs or src/main.rs (the sample fixture is code_sources/rust-hello/src/lib.rs). There is no environment-variable entrypoint override.
Logging
Use eprintln! (stderr) for logs in the serve loop β not println!.
What it compiles to
The target is selected with --rust-target native|wasm:
rust-nativeβ a native Linux binary, default targetx86_64-unknown-linux-gnu(dynamically linked).rust-wasmβwasm32-wasip2(a Component Model module that runs under Wasmtime).
Toolchain: Rust 1.93.
Deploy
Rust needs an explicit compile step before publishing:
dodil ignite app create hello --runtime rust --rust-target native
dodil ignite draft save org:hello --code ./
dodil ignite draft compile org:hello
dodil ignite draft publish org:hello
dodil ignite invoke org:hello -p '{"message": "hi there"}'See also
- Code & Runtimes β the compile vs image paths
- Python compile contract
- Go compile contract
- Deno compile contract
- Container images β bring or build your own container
- Quickstart