Rust functions as WASIp3 components

Fast Rust functions without the platform tax.

Faasta gives you the useful parts of serverless without containers, per-service boilerplate, or hand-rolled tenancy. Rust handlers compile to WASIp3 wasi:http/service components, run warm inside Wasmtime, and receive SQL, KV, and blob storage through wasi-cloud-core host capabilities.

Warm reuse precompiled components stay ready for low-latency requests
Async I/O host calls yield through the Tokio and Wasmtime request path
No containers lighter deploys with capability-level isolation

Why Faasta exists.

Most small services should not need their own container image, runtime glue, database tenancy code, object-store naming scheme, and deploy pipeline. Faasta keeps the unit of deployment small: one async Rust handler, one WASIp3 component, and host-managed capabilities for fast startup, predictable isolation, and shared distributed backends.

Small deployment unit

Application crates depend on faasta. The SDK macro exports the service world, and the CLI hides the WASIp3 build details.

Performance-oriented runtime

Components are validated, precompiled, cached, and invoked in-process. Async SQL, KV, blob, and response body work can yield instead of blocking the server.

Tenant-scoped storage

Guests open simple names from the wasi-cloud-core capability APIs. Faasta maps those names to per-function SQL schemas, object prefixes, and key prefixes.

One runtime, many requests.

Faasta gets its cost advantage by amortizing the expensive parts. A single server process owns sockets, TLS, scheduling, Wasmtime engines, compiled component caches, database pools, and capability providers. Individual requests only enter a tenant-scoped component instance and await shared async host services.

Where the overhead lives

Faasta node
Tokio Wasmtime fn A fn B fn C SQL pool
Container per service
runtime A runtime B runtime C
VM per service
guest OS A guest OS B guest OS C
Managed edge/serverless
vendor runtime metered CPU cold starts microVMs bound services

The important trick is not magic: keep the platform hot once, then multiplex lots of small isolated components through it.

Efficiency shape

Faasta shared WASI runtimelowest multi-tenant overhead
Cloudflare Workers style isolateefficient, but JS can pay GC/JIT overhead
Lambda style functionscold starts plus microVM/runtime init
Docker service per functionduplicated runtime memory
VM per functionduplicated kernel and userspace

This is an architectural comparison, not a benchmark. Actual cost depends on traffic shape, memory limits, regional networking, storage backends, and how much idle capacity you keep warm.

Memory and CPU pressure

Memory overhead

Faasta shared WASI runtimeengine, pools, and host services shared
Workers style isolateisolate heap per workload
Lambda style functionreserved memory and microVM envelope
Container per functionruntime duplicated per image
VM per functionguest kernel and userspace duplicated

CPU overhead

Faasta shared WASI runtimeawait points reuse one scheduler
Workers style isolatedispatch plus possible JIT and GC work
Lambda style functioncold start, runtime bootstrap, metering
Container per functionprocess and runtime duplication
VM per functionscheduler and virtualization layers

The win is highest for many small I/O-heavy functions: while one request waits on SQL, KV, blobs, or a response body, the same process can keep polling other tenants without starting another container, microVM, or guest OS.

Usage

The CLI wraps the component build. Most projects should start with cargo faasta new, edit the generated handler, then build and deploy with the same commands.

Create and deploy

cargo install cargo-faasta
cargo faasta new hello-site
cd hello-site
cargo faasta build
cargo faasta deploy

HTML response

use faasta::http::Html;

#[faasta::handler]
async fn handle() -> faasta::Result<Html<String>> {
    Ok(Html("<h1>Hello from Faasta</h1>".to_string()))
}

JSON response

use faasta::http::Json;
use serde::Serialize;

#[derive(Serialize)]
struct Output {
    ok: bool,
}

#[faasta::handler]
async fn handle() -> faasta::Result<Json<Output>> {
    Ok(Json(Output { ok: true }))
}

Injected storage

use faasta::{blob::Blobs, http::Json, kv::Kv, sql::Sql};

#[faasta::handler]
async fn handle(kv: Kv, sql: Sql, blobs: Blobs) -> faasta::Result<Json<Output>> {
    kv.bucket("cache").set("last", "hello").await?;
    sql.exec("CREATE TABLE IF NOT EXISTS hits (message TEXT)", ()).await?;
    blobs.container("uploads").create_if_missing().await?;
    Ok(Json(Output { ok: true }))
}

Backends without new guest APIs.

Faasta keeps guest code stable while swapping host providers behind the wasi-cloud-core capability contracts. Local development can stay simple; multi-node deployments point every server at the same Postgres, Garage/S3, and Valkey services.

Capability Local default Distributed backend Environment
SQL Per-function SQLite files Postgres schema per function FAASTA_SQL_BACKEND=postgres
Blob In-memory provider Garage or S3-compatible object storage FAASTA_BLOB_BACKEND=s3
KV In-memory provider Valkey with tenant prefixes FAASTA_KV_BACKEND=valkey

Build wraps the target details.

Faasta targets WASIp3 components. The Rust target is still evolving, so the CLI owns the target name and artifact path. Application docs should teach the Faasta workflow instead of asking users to memorize component build internals.

cargo faasta build
# wraps the WASIp3 component build

cargo faasta deploy
# uploads target/wasm32-wasip3/release/<crate>.wasm by default