isala404
forge
Rust

Rust framework that compiles entire infrastructure into one binary

Last updated Jul 2, 2026
82
Stars
3
Forks
0
Issues
0
Stars/day
Attention Score
38
Language breakdown
Rust 86.4%
Python 8.4%
JavaScript 4.3%
Ruby 0.2%
Shell 0.1%
Elixir 0.1%
โ–ธ Files click to expand
README

Forge - the standard library for agent-built SaaS

Every app needs the same plumbing, and the usual answer is a separate service for each piece:

  • Redis for caching and sessions
  • a queue for background jobs
  • object storage for uploads
  • an auth service for logins and sessions
  • a cron runner for scheduled work
  • a rate limiter
Six things to provision, secure, mock in tests, and learn before you ship a feature. It's worse for an AI agent building the app, where each service is more to wire up and another API to get wrong.

Forge does all of it in one library, with the same API in Rust, Node, and Python.

One connection, eight primitives

npm install forgelib

Configuration lives in a forge.toml at your project root. init() reads it and instantiates the runtime; string values may reference the environment as ${VAR}:

[postgres]
url = "${DATABASE_URL:-}"
embedded = true

Set DATABASE_URL to use a managed or shared Postgres. Leave it unset and Forge downloads and runs Postgres for you (data persists in .forge/pg) โ€” built into the Node and Python packages, behind the embedded cargo feature in Rust. Forge supports Postgres 17+.

Omit settings you do not need; Forge applies production-safe defaults for the rest.

import { ForgeClient } from "forgelib";

const forge = await ForgeClient.init(); // instantiates the runtime from ./forge.toml

// auth: argon2 password hashing and sessions const hash = await forge.hashPassword(password); const session = await forge.createSession(userId);

// rate limit: 20 attempts per minute, keyed by email const limit = await forge.rateLimitCheck("login", email, 20, 60); if (!limit.allowed) throw new Error("slow down");

// key/value: TTL cache and atomic counters await forge.kv<typeof profile>(user:${userId}).set(profile, { ttlSeconds: 3600 }); const views = await forge.kvIncr(views:${userId}, 1);

// queue: background jobs await forge.queue<{ to: string }>("emails").enqueue({ to: email });

// pub/sub: fan an event out to subscribers await forge.topic<{ userId: string }>("user.created").publish({ userId });

// blob: store a file, hand back a link that expires in an hour await forge.blobPut(exports/${userId}.csv, csv, "text/csv"); const link = await forge.blobPresignDownload(exports/${userId}.csv, 3600);

// schedule: recurring work on a cron await forge.scheduleCron("nightly-report", "0 0 *", "reports", "{}");

// feature flags: roll a feature out to 25% of users await forge.setFlagPercent("new-ui", 25); const newUi = await forge.flag("new-ui", false, userId);

The same in Rust

cargo add forgelib
use std::time::Duration;
use forgelib::{
    Forge, Bytes, SetOpts, EnqueueOpts, PutOpts,
    ScheduleOpts, SessionOpts, Limit, FlagRule, EvalCtx,
};

let forge = Forge::init().await?; // instantiates the runtime from ./forge.toml

// auth let hash = forge.auth().hash_password(&password).await?; let session = forge.auth().createsession(&userid, SessionOpts::default()).await?;

// rate limit let limit = forge.ratelimit() .check("login", &email, Limit::perduration(20, Duration::fromsecs(60))) .await?;

// key/value forge.kv().set(&format!("user:{user_id}"), profile.into(), SetOpts::new().withttl(Duration::fromsecs(3600))).await?; let views = forge.kv().incr(&format!("views:{user_id}"), 1).await?;

// queue forge.queue().enqueue("emails", payload.into(), EnqueueOpts::new()).await?;

// pub/sub forge.pubsub().publish("user.created", Bytes::from(event)).await?;

// blob forge.blob().put(&key, body, PutOpts::new()).await?; let link = forge.blob().presigndownload(&key, Duration::fromsecs(3600)).await?;

// schedule forge.schedule().cron("nightly-report", "0 0 *", "reports", Bytes::new(), ScheduleOpts::new()).await?;

// feature flags forge.config().set_flag("new-ui", FlagRule::Percent(25)).await?; let newui = forge.config().flag("new-ui", false, &EvalCtx::user(userid)).await;

The same in Python

pip install forgelib
import forgelib

forge = await forgelib.ForgeClient.init() # instantiates the runtime from ./forge.toml

auth

hash = await forge.hash_password(password) session = await forge.createsession(userid)

rate limit

limit = await forge.ratelimitcheck("login", email, 20, 60) if not limit.allowed: raise RuntimeError("slow down")

key/value

await forge.kv(f"user:{userid}").set(profile, ttlseconds=3600) views = await forge.kvincr(f"views:{userid}", 1)

queue

await forge.queue("emails").enqueue({"to": email})

pub/sub

await forge.topic("user.created").publish({"userid": userid})

blob

await forge.blobput(f"exports/{userid}.csv", csv, "text/csv") link = await forge.blobpresigndownload(f"exports/{user_id}.csv", 3600)

schedule

await forge.schedule_cron("nightly-report", "0 0 *", "reports", "{}")

feature flags

await forge.setflagpercent("new-ui", 25) newui = await forge.flag("new-ui", False, userid)

What you get

| Primitive | What it does | | --- | --- | | key/value | get, set, mget, incr, compare-and-swap, prefix scan, TTLs | | queue | enqueue and dequeue with acks, retries, delays, dedup, depth | | pub/sub | publish and subscribe on topics | | blob | put, get, delete, presigned upload and download URLs | | auth | password hashing, sessions, API keys | | rate limit | token-bucket or sliding-window checks | | schedule | cron and one-off jobs | | config | settings and feature flags with percentage rollout |

By default every primitive runs on one Postgres database, so there's nothing else to operate. When one needs to scale, move that piece onto its own backend without changing your code.

Test on memory, ship on Postgres

The memory and Postgres backends pass the same conformance suite, so tests run in-process with no database and behave the way production will. Pick the backend in forge.toml, using a ${VAR} reference so the same file flips between tests and production from the environment.

[backends]
default = "${FORGEBACKEND:-postgres}"  # FORGEBACKEND=memory in tests

[postgres] url = "${DATABASE_URL:-}" embedded = true

Build it with an agent

Forge's API isn't in any model's training data, so a coding agent won't know it cold. Install the forge-idiomatic-developer skill so your agent learns the conventions before it writes any Forge code.

npx skills add isala404/forge

It teaches which primitive fits which task and the idioms for each language, so you get working code instead of guesses.

Not in scope

  • The APIs are a shared subset, not a full reimplementation. key/value covers the Redis commands most apps use, not Lua scripts or sorted sets. blob does CRUD and presigned URLs, not S3 lifecycle rules.
  • auth is the essentials: password hashing, sessions, and API keys, enough to have working auth in minutes while you prototype. For OAuth, 2FA, or email verification, bring Clerk, Firebase, or a dedicated provider.
  • Forge ships two backends, memory and Postgres, plus local disk for blob. If you need Redis or S3, implement the primitive's trait and inject it, or use that service directly.
  • Not an ORM or a web framework. Your tables and routes stay yours.

Examples

Three full apps in examples/, each built on the Rust, Node, and Python backends with a React frontend.

  • todo: accounts, lists, and a background audit queue
  • links: a URL shortener with click counts, QR images, and analytics
  • chat: real-time messaging with presence

License

MIT. Do whatever you want.

Postgres is enough.
Quick Start ยท Examples ยท Discussions

๐Ÿ”— More in this category

ยฉ 2026 GitRepoTrend ยท isala404/forge ยท Updated daily from GitHub