Durable by default
Steps, fetches, SQL and sleeps are journaled. A retry replays what already happened instead of doing it twice, and a run can sleep for days and survive restarts.
Backend runtime · Rust · WebAssembly
Write operations in Rust. fncosmos runs each one in its own sandbox, records every step it takes, and puts the values right next to your code.
POST /notes { "text": "ship it" }let db = ctx.resource("db")?;
db.transaction("insert", |tx| {
tx.query_opt("insert …", …)
}) ✓ attempt 1 · 4.2 msHow it works
// Declared with a builder, read when you deploy.
operation("my-notes")
.http("GET", "/me/notes")
.authenticated()
.handler(|ctx, _: ()| {
let user = ctx.require_auth()?;
ctx.resource("db").query_as::<Note>(
"select * from notes where owner = $1",
&[user.subject.into()],
)
})import { createAuthClient } from "@fncosmos/client";
import { createClient } from "./fncosmos.ts"; // generated
const auth = createAuthClient({ url: AUTH_URL });
const api = createClient({ baseUrl, token: auth.token });
auth.signInWith("github");
const notes = await api.notes.myNotes(); // Note[]Steps, fetches, SQL and sleeps are journaled. A retry replays what already happened instead of doing it twice, and a run can sleep for days and survive restarts.
Every attempt runs in a fresh WebAssembly instance with its own memory and CPU limits. Outgoing requests pass a network fence. Many projects share one process safely.
One builder declares an operation and what triggers it: its own route, a schedule, or a call from the CLI. Public, keyed, signed-in or internal-only.
Pooled connections, queries journaled like any other step, transactions that replay once committed, migrations on deploy, and row types generated from the database.
Argument and result types come from your Rust code. One command writes a TypeScript client where a wrong argument is a compile error.
Passwords, Google and GitHub, from fncosmos auth or any OpenID provider. Mark an operation .authenticated() and read the user with ctx.auth().