Skip to content
solana_kit

Choosing a runtime#

The portable crates (solana_kit_core, solana_kit_client and the program clients) have no networking code. You choose where your code runs by adding one adapter crate. That crate owns the HTTP and WebSocket transport for its host. Every HTTP adapter (NativeHttp, BrowserHttp, WasiHttp, GuestHttp) implements the same solana_kit_client::Transport trait, so your RPC code is identical everywhere and only the line that constructs the transport changes. WebSockets take a separate path: each adapter's socket implements solana_kit_client::subscriptions::TextSocket for the subscription Session, not Transport.

Native

solana_kit_native

Tokio HTTP/1, verified TLS and WebSockets, with deadlines and cancel-on-drop.

Browser

solana_kit_browser

Window Fetch and the browser WebSocket, with local (non-Send) futures.

WASI

solana_kit_wasi

Preview2 HTTP and sockets, driven by a caller-owned Reactor.

LeptosKit

solana_kit_leptoskit

An interpreted Wasm guest calls named services that a native host owns.

Compare the runtimes#

RuntimeTargetCrateHTTPWebSocketStatus
NativeHost targets with Tokiosolana_kit_nativeNativeHttp: HTTP/1 over Hyper, rustls TLSNativeWebSocket: WS and WSS text socketsHTTP and WebSocket run in CI on Ubuntu, macOS and Windows
Browserwasm32-unknown-unknown in a browser Windowsolana_kit_browserBrowserHttp: Window FetchBrowserWebSocket: browser WebSocketHTTP and text sockets run in CI in Chrome; workers, webviews and mobile browsers are unverified
WASIwasm32-wasip2solana_kit_wasiWasiHttp: wasi:httpWasiWebSocket (feature websocket): wasi:sockets plus guest TLSHTTP runs under Wasmtime 50; the socket path is newer and still partly pending
LeptosKitInterpreted wasm32-unknown-unknown guest plus a native hostsolana_kit_leptoskitGuestHttp in the guest, HttpDriver or HttpHost in the hostGuestWebSocket and SocketDriverGuest HTTP runs headless in CI; sockets and installed-app journeys are still pending

Preview1 (wasm32-wasip1) and plain Wasm without a browser still compile the portable client, but no networking adapter exists for them.

The common shape#

All four adapters follow the same rules:

  • You own the runtime. No adapter starts an executor, spawns a detached task, pools connections or installs a global.
  • You pass configuration in. Endpoints, headers and deadlines are explicit, and nothing is read from the environment. Trust roots are yours to supply only where the adapter exposes them (NativeHttp's TlsRoots); the browser, the WASI host and the LeptosKit host apply their own TLS trust policy.
  • Bounded by default. Reply bodies are capped by the client's request budget. Each transport adds its own deadlines.
  • Drop cancels. Dropping an in-flight exchange releases its owned network work. Nothing is retried or redirected automatically.
  • Diagnostics are redacted. Errors omit endpoints and header values. The original cause stays reachable through std::error::Error::source.

Construct a client the same way in every runtime:

Native

use solana_kit_client::{Client, Limits};
use solana_kit_native::{HttpConfig, NativeHttp};

let transport = NativeHttp::new("https://rpc.invalid/", HttpConfig::default())?;
let client = Client::new(transport, Limits::default());

Browser

use solana_kit_browser::{BrowserHttp, HttpConfig};
use solana_kit_client::{Client, Limits};

let transport = BrowserHttp::new("https://rpc.invalid/", HttpConfig::default())?;
let client = Client::new(transport, Limits::default());

WASI

use solana_kit_client::{Client, Limits};
use solana_kit_wasi::{Reactor, WasiHttp};
use std::time::Duration;

let reactor = Reactor::default();
let transport = WasiHttp::new(
    reactor.clone(),
    "https://rpc.invalid/",
    Duration::from_secs(30),
    Vec::new(),
)?;
let client = Client::new(transport, Limits::default());

LeptosKit

use solana_kit_client::{Client, Limits};
use solana_kit_leptoskit::GuestHttp;

// The guest names a service; the native host decides where it goes.
let transport = GuestHttp::new("balance-service")?;
let client = Client::new(transport, Limits::default());

Constructing a transport sends nothing. The first request happens when you poll a call. See RPC for the calls you can make once you have a client.

How to pick#

  • A CLI, server, bot or desktop backend: use Native.
  • A web page: use Browser. Add its wallet feature to talk to browser wallets.
  • A WebAssembly component in a WASI host such as Wasmtime: use WASI. The embedding host enforces network policy and TLS for HTTP.
  • A LeptosKit desktop or mobile app: use LeptosKit. The guest uses guest; the native shell uses host.
  • Wallet connections on any of these: read Wallets.

One test suite, five hosts#

The portable core is checked by one conformance suite, solana_kit_conformance. cargo xtask all runs it natively, in Chrome, in Wasmtime Preview 1 and Preview 2, and in a headless LeptosKit WasmHost. Each host can also run alone:

cargo xtask native
cargo xtask browser
cargo xtask wasi
cargo xtask leptoskit

cargo xtask browser needs CHROME and CHROMEDRIVER set to the Chrome binary and its matching driver, and cargo xtask wasi needs WASMTIME set to Wasmtime 50.0.0. cargo xtask native and cargo xtask leptoskit need neither. See Verification for the full setup. This suite covers the portable core. Each transport has its own separate CI workflow.

esc