Wasmtime host capability for SQL database access from WebAssembly components. Uses sqlx as the underlying database driver.
Note: This library uses experimental async features from wasmtime component model. Required versions: wasmtime 0.41+, wit-bindgen 0.51+
- Connection pooling — efficient connection management via sqlx
- Transactions — full support for begin/commit/rollback with automatic rollback on drop
- Async support — fully async API using wasmtime component model async
PostgreSQL — Supported
- Codecs: int16/32/64, float32/64, string, bool, json, uuid, hstore, date, time, timestamp, timestamptz, interval, inet, cidr, macaddr, numeric
SQLite — Supported
- Codecs: int64, float64, string, blob, bool, json, uuid, date, time, datetime, datetime-utc
MySQL — Planned
- Driver ready, codecs pending
Missing a codec? Please create an issue with your use case!
- examples/host.rs — Host implementation (wasmtime runtime)
- examples/guest-app/ — Guest WASM component example
Add dependency:
[dependencies]
wasm-sql = { version = "0.1.5", features = ["postgres"] } # or "sqlite"Set up the host:
use std::sync::Arc;
use wasm_sql::{SqlHostState, SqlHostStateView};
use wasm_sql::sqldb::SqlDB;
use wasm_sql::sqldb::sqlx::postgres::PgPoolOptions;
use wasmtime::component::Linker;
// Your state struct
struct HostState {
sql: SqlHostState,
// ... other fields (e.g., WasiCtx if needed)
}
impl SqlHostStateView for HostState {
fn sql_host_state(&mut self) -> &mut SqlHostState {
&mut self.sql
}
}
// Create database pool
let pool = PgPoolOptions::new()
.max_connections(5)
.connect("postgres://user:pass@localhost/db")
.await?;
let sql_db = Arc::new(SqlDB::new(pool));
// Add wasm-sql imports to linker
let mut linker: Linker<HostState> = Linker::new(&engine);
wasm_sql::add_to_linker(&mut linker)?;
// Create state
let state = HostState {
sql: SqlHostState::new(sql_db),
};See full working example in examples/host.rs.
See full example in examples/guest-app/.
Add dependency:
[dependencies]
wit-bindgen = "0.51"Generate bindings and use:
use bindings::wasm_sql::{
core::query::{self, QueryExecutor},
core::query_types::{SqlArguments, SqlQuery},
core::util_types::Error as SqlError,
postgres::codecs,
};
use bindings::wasm_sql::core::{pool, transaction::Transaction};
mod bindings {
wit_bindgen::generate!({
world: "your-app-world",
path: ["path/to/wasm-sql/wit", "path/to/wasm-sql/wit/postgres", "./wit"],
});
}
// Execute a parameterized query
async fn insert_user(name: &str, age: i32) -> Result<(), SqlError> {
let args = SqlArguments::new();
codecs::push_string(Some(name), &args)?;
codecs::push_int32(Some(age), &args)?;
let query = SqlQuery {
sql: "INSERT INTO users (name, age) VALUES ($1, $2)".to_string(),
args: Some(args),
persistent: Some(true),
};
query::execute(query, QueryExecutor::Pool).await?;
Ok(())
}
// Fetch data and decode results using codecs
async fn get_user(id: i64) -> Result<(String, i32, String), SqlError> {
use bindings::wasm_sql::core::codecs::ColumnIndex;
let args = SqlArguments::new();
codecs::push_int64(Some(id), &args)?;
let query = SqlQuery {
sql: "SELECT name, age, email FROM users WHERE id = $1".to_string(),
args: Some(args),
persistent: Some(true),
};
let result = query::fetch_all(query, QueryExecutor::Pool).await?;
// Decode values from row 0 using get_* functions
let name = codecs::get_string(&result, &(0, ColumnIndex::ColumnName("name")))?
.ok_or(SqlError::Decode("name is null".to_string()))?;
let age = codecs::get_int32(&result, &(0, ColumnIndex::ColumnName("age")))?
.ok_or(SqlError::Decode("age is null".to_string()))?;
let email = codecs::get_string(&result, &(0, ColumnIndex::ColumnName("email")))?
.ok_or(SqlError::Decode("email is null".to_string()))?;
Ok((name, age, email))
}┌─────────────────────┐
│ WASM Component │
└─────────┬───────────┘
│ WIT imports
▼
┌─────────────────────┐
│ wasm-sql (host) │
└─────────┬───────────┘
│ sqlx
▼
┌─────────────────────┐
│ Database │
│ (PostgreSQL/MySQL/ │
│ SQLite) │
└─────────────────────┘
wasm-sql:core/host— Core SQL operations (pool, connections, transactions, queries)wasm-sql:postgres/host— PostgreSQL-specific type codecswasm-sql:sqlite/host— SQLite-specific type codecs
MIT