Skip to main content

Forge Documentation

Forge is a Rust framework that compiles backend functions (queries, mutations, jobs, crons, workflows, and webhooks) into a single runtime backed by PostgreSQL. It generates frontend bindings from the same Rust source of truth, with first-class support for SvelteKit and Dioxus today.

Documentation map

  • Start: First App, Project Anatomy
  • Build: Queries, mutations, jobs, workflows, scheduled tasks, webhooks, and reactivity
  • Connect: Generated TypeScript client, authentication, caching, and frontend usage
  • Ship: Configuration, deployment, and testing
  • Scale: Multiple nodes, worker pools, and global deployments
  • Reference: CLI and configuration options

Quick start (development)

curl -fsSL https://tryforge.dev/install.sh | sh
forge new my-app --template with-svelte/minimal
cd my-app
forge dev

Runs Docker Compose with PostgreSQL, backend (cargo-watch), and the selected frontend target. Use forge dev down --clear to reset. Choose a with-dioxus/* template if you want a Dioxus frontend instead of SvelteKit.

Queries and mutations

#[forge::query]
pub async fn list_todos(ctx: &QueryContext) -> Result<Vec<Todo>> {
sqlx::query_as!(Todo, "SELECT * FROM todos")
.fetch_all(ctx.db())
.await
.map_err(Into::into)
}
// Auto-generated, type-safe
import { listTodos$ } from '$lib/forge';

const todos = listTodos$();

Queries and mutations are exposed as RPC endpoints under /_api/rpc and used by the generated frontend bindings. SvelteKit projects get TypeScript clients and stores; Dioxus projects get Rust bindings and hooks. Subscriptions use PostgreSQL LISTEN/NOTIFY plus a SSE connection to push updates.

Background jobs

#[forge::job(
priority = "high",
retry(max_attempts = 5, backoff = "exponential")
)]
pub async fn send_email(ctx: &JobContext, args: EmailArgs) -> Result<()> {
ctx.progress(0, "Sending...")?;
// ...
ctx.progress(100, "Sent")?;
Ok(())
}

Jobs are stored in PostgreSQL and claimed with FOR UPDATE SKIP LOCKED. Retry policy, priority, and progress updates are stored alongside the job record.

Webhooks

#[forge::webhook(
path = "/hooks/stripe",
signature = WebhookSignature::hmac_sha256("Stripe-Signature", "STRIPE_WEBHOOK_SECRET"),
idempotency = "header:Idempotency-Key",
)]
pub async fn stripe(ctx: &WebhookContext, payload: Value) -> Result<WebhookResult> {
ctx.dispatch_job("process_payment", payload.clone()).await?;
Ok(WebhookResult::Accepted)
}

Webhook handlers run inside the Forge runtime and can validate signatures, enforce idempotency, and enqueue background work.

Workflows

#[forge::workflow]
pub async fn onboarding(ctx: &WorkflowContext, user_id: Uuid) -> Result<()> {
ctx.step("welcome_email", || async {
send_welcome(user_id).await
})
.run()
.await?;

ctx.sleep(Duration::from_secs(3 * 24 * 60 * 60)).await?;

ctx.step("check_activation", || async {
check_user_active(user_id).await
})
.compensate(|_| async move { send_reminder(user_id).await })
.run()
.await?;

Ok(())
}

Workflow state is persisted in PostgreSQL so steps resume after restarts. Durable timers and compensation handlers are recorded per step.

PostgreSQL integration

Forge relies on core PostgreSQL features for coordination and data propagation:

  • FOR UPDATE SKIP LOCKED for job queues
  • LISTEN/NOTIFY for real-time subscriptions
  • Advisory locks for leader election and migration coordination
  • WAL durability for workflow and job state
  • sqlx macros plus .sqlx/ offline cache for compile-time query validation

Build output

cargo build --release
./target/release/my-app

The release binary embeds the Forge runtime and can optionally bundle the frontend build using the embedded-frontend feature.

Requirements

Forge requires PostgreSQL 15+ and is released under the MIT License.

Next: First App