Quickstart
Forge is one dependency. You point it at a Postgres database it can own, call
init(), and you have all eight primitives on a single client. This page gets you
from nothing to your first calls.
Install
Section titled “Install”npm install forgelibpip install forgelibcargo add forgelibGive Forge a database
Section titled “Give Forge a database”Forge keeps its own state in Postgres. It owns its forge_* tables and runs its
migrations for you when the app starts, so give it a database (or its own schema)
and keep your product tables separate.
# any Postgres works; create one for Forge to owncreatedb myappWrite forge.toml
Section titled “Write forge.toml”Configuration lives in a forge.toml at your project root. It’s the single source
of config: init() reads it and builds the runtime. String values can read the
environment with ${VAR} or ${VAR:-default}, so the same file works in tests and
in production.
[postgres]url = "${DATABASE_URL:-postgres://localhost/myapp}"Everything else has a production-safe default, so this is enough to start. The full list of settings is in Configuration.
Make your first calls
Section titled “Make your first calls”init() reads forge.toml, migrates the system database, and returns a client.
The same calls look like this in each language. (Pick a language once and the tabs
on this site follow your choice.)
import { ForgeClient } from "forgelib";
const forge = await ForgeClient.init(); // reads ./forge.toml, runs migrations
// auth: hash a password, open a sessionconst hash = await forge.hashPassword(password);const token = await forge.createSession(userId);
// key/value: an atomic counterconst views = await forge.kvIncr(`views:${userId}`, 1);
// queue: hand work to the backgroundawait forge.queue<{ to: string }>("emails").enqueue({ to: email });
// rate limit: 20 attempts per minute, keyed by emailconst limit = await forge.rateLimitCheck("login", email, 20, 60);if (!limit.allowed) throw new Error("slow down");import forgelib
forge = await forgelib.ForgeClient.init() # reads ./forge.toml, runs migrations
# auth: hash a password, open a sessionhash = await forge.hash_password(password)token = await forge.create_session(user_id)
# key/value: an atomic counterviews = await forge.kv_incr(f"views:{user_id}", 1)
# queue: hand work to the backgroundawait forge.queue("emails").enqueue({"to": email})
# rate limit: 20 attempts per minute, keyed by emaillimit = await forge.rate_limit_check("login", email, 20, 60)if not limit.allowed: raise RuntimeError("slow down")use std::time::Duration;use forgelib::{Forge, SessionOpts, EnqueueOpts, Limit};
let forge = Forge::init().await?; // reads ./forge.toml, runs migrations
// auth: hash a password, open a sessionlet hash = forge.auth().hash_password(&password).await?;let token = forge.auth().create_session(&user_id, SessionOpts::default()).await?;
// key/value: an atomic counterlet views = forge.kv().incr(&format!("views:{user_id}"), 1).await?;
// queue: hand work to the backgroundforge.queue().enqueue("emails", payload.into(), EnqueueOpts::new()).await?;
// rate limit: 20 attempts per minute, keyed by emaillet limit = forge.ratelimit() .check("login", &email, Limit::per_duration(20, Duration::from_secs(60))) .await?;if !limit.allowed { /* return 429 */ }One shape difference is worth noting. Rust reaches each primitive through an accessor
and uses option structs, like forge.kv().set(key, value, SetOpts::new()). Node and
Python keep the exact raw methods on the client (forge.kvSet(...), forge.kv_set(...))
for contract parity, and add native JSON handles (forge.kv<T>(key),
forge.queue<T>(name), forge.kv(key), forge.queue(name)) for the app values you
want typed in day-to-day code.
Run the background work
Section titled “Run the background work”Forge doesn’t start any threads of its own. Enqueued jobs sit in the queue until a worker leases them, and schedules only fire when something ticks them. In a typical app you run a worker for each queue and one loop that ticks the scheduler and does housekeeping. Operations covers both, and Recipes shows them inside real handlers.