Slim down your binary
By default, every Forge app pulls every subsystem: HTTP gateway, jobs, workflows, cron, daemons, signals, MCP, OAuth, OpenTelemetry, GeoIP. Most production apps use a subset — feature flags let you compile only what you need.
Quick start
# Cargo.toml — worker-only binary (no HTTP)
[dependencies]
forge = { version = "0.9", default-features = false, features = ["worker"] }
| Preset | What's included | When to use |
|---|---|---|
full | Everything (default) | Standard apps, gateway + workers |
worker | jobs, workflows, cron, daemons, otel | Background-only nodes |
api | gateway, otel | Read-heavy API servers (no workers) |
minimal | gateway only | Smallest gateway binary, no OTel |
Individual features
If the presets don't fit, compose your own from primitives:
| Feature | Pulls in |
|---|---|
gateway | HTTP server (axum, tower), JWT auth, OAuth, MCP, webhooks, signals |
jobs | PG-backed job queue and worker |
workflows | Durable workflow executor |
cron | Cron scheduler (leader-elected) |
daemons | Long-running daemon runner |
geoip | Bundled IP-to-country DB + MaxMind reader (heavy) |
otel | OpenTelemetry trace/metric/log exporters |
Example:
forge = { version = "0.9", default-features = false, features = ["gateway", "jobs", "otel"] }
What you save
Approximate cargo build --release impact, measured on the demo template
on a clean checkout:
| Configuration | Compile time | target/ size |
|---|---|---|
full (default) | baseline | baseline |
worker | -55% | -65% |
api | -25% | -30% |
minimal | -65% | -75% |
The biggest individual savings come from disabling otel (skips ~5 OTel
crates + protobuf) and geoip (skips a build-time database download — also
unblocks builds in air-gapped environments).
Air-gapped / offline builds
The db_ip crate behind the geoip feature downloads its database at
build time. If your CI lacks network access, disable geoip:
forge = { version = "0.9", default-features = false, features = [
"gateway", "jobs", "workflows", "cron", "daemons", "otel"
] }
Compile-time errors when a macro doesn't match the feature set
If you write #[forge::job] but don't enable the jobs feature, you'll
get an error at the generated forge::AutoJob reference. Same pattern for
#[forge::cron]/AutoCron, #[forge::workflow]/AutoWorkflow,
#[forge::daemon]/AutoDaemon, #[forge::webhook]/AutoWebhook,
#[forge::mcp_tool]/AutoMcpTool. Fix by enabling the feature (or
remove the unused handler).
Build profile tuning
The workspace also ships profile presets that trade off build speed and binary size:
dev(default): line-only debug info, 256 codegen units, incremental. Optimized for fast iteration; produces large but fast-rebuilding artifacts.release: full LTO, single codegen unit, stripped symbols. Slow to build, smallest binary.release-fast: release with LTO disabled and 16 codegen units. Use for smoke tests and ad-hoc benchmarks where you want optimized code without the 30-90 second LTO link stall:cargo build --profile release-fast
Linker tuning
Default linkers are slow. Drop minutes off incremental builds with mold
(Linux) or lld (macOS):
# Linux
sudo apt install mold
export RUSTFLAGS="-C link-arg=-fuse-ld=mold"
# macOS
export RUSTFLAGS="-C link-arg=-fuse-ld=lld"
Or globally cache rustc output across cargo clean cycles with sccache:
cargo install --locked sccache
export RUSTC_WRAPPER=sccache