Skip to main content

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"] }
PresetWhat's includedWhen to use
fullEverything (default)Standard apps, gateway + workers
workerjobs, workflows, cron, daemons, otelBackground-only nodes
apigateway, otelRead-heavy API servers (no workers)
minimalgateway onlySmallest gateway binary, no OTel

Individual features

If the presets don't fit, compose your own from primitives:

FeaturePulls in
gatewayHTTP server (axum, tower), JWT auth, OAuth, MCP, webhooks, signals
jobsPG-backed job queue and worker
workflowsDurable workflow executor
cronCron scheduler (leader-elected)
daemonsLong-running daemon runner
geoipBundled IP-to-country DB + MaxMind reader (heavy)
otelOpenTelemetry 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:

ConfigurationCompile timetarget/ size
full (default)baselinebaseline
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