Overview
Every integration is an optional package — forze[postgres], forze[redis],
and so on — that implements Forze contracts for one backend. They share a common
shape: a client and ports in kernel/, concrete adapters/, and execution/
deps + lifecycle modules you wire exactly as shown in
Wiring. Your handlers never import them; they resolve
ports from the context.
Per-backend pages cover the specifics — configuration, schema expectations, and
caveats. The authoritative, always-current set is the [project.optional-dependencies]
extras in pyproject.toml; each forze[<name>] maps to the <name> extra.
Available integrations¶
| Area | Extras |
|---|---|
| Data | postgres · mongo · firestore · neo4j · redis · s3 · gcs · meilisearch · bigquery · clickhouse · duckdb |
| Messaging | kafka · rabbitmq · sqs |
| Workflows | temporal · inngest |
| Inbound | fastapi · socketio · mcp |
| Identity | authn · oidc |
| Secrets & keys | vault · kms-aws · kms-gcp · kms-yc |
| Outbound | http · inference-http · inference-sagemaker |
Each row maps to a forze[<extra>] package; their precise contract coverage is
on each integration's page. Two key backends need no extra at all: the
self-hosted local KMS and the in-memory mock.
The remaining extras are not backend integrations: dst and cli are tooling
(deterministic simulation testing and the forze
command-line tool), mock-server serves the in-memory mock over HTTP,
sandbox-container is the container tier of the
sandbox execution plane, observability adds the OTLP
exporter for telemetry, and zstd adds the zstd
codec for portable archives.
Install one or several at once — uv add 'forze[fastapi,postgres,redis]'.
Connection settings¶
Every integration ships a <Backend>Settings model holding the endpoint, the credentials
and the client knobs a deployment sets — the thing an application would otherwise declare
for itself, once per backend, and get subtly wrong. They are plain pydantic BaseModels,
so you mount them on your own settings root and the environment fills them in:
from forze_postgres import PostgresSettings
from forze_rabbitmq import RabbitMQSettings
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_nested_delimiter="__")
postgres: PostgresSettings = PostgresSettings()
rabbitmq: RabbitMQSettings = RabbitMQSettings()
POSTGRES__HOST, RABBITMQ__VHOST and the rest then populate them. The prefix, the
delimiter and the extra-key policy stay yours — Forze ships no BaseSettings root,
because those are deployment decisions.
Each model exposes what its wiring takes:
| It gives you | Where it goes |
|---|---|
.dsn / .uri / .url / .address / .servers |
the lifecycle step's connection argument |
.config |
the same step's config=, as the backend's own config object |
.require_host() / .require_endpoint() / .require_project_id() |
wherever the wiring wants a plain str |
lifecycle = LifecyclePlan.from_modules(
postgres_lifecycle_step(dsn=settings.postgres.dsn, config=settings.postgres.config),
)
Three rules hold across all of them:
- A missing endpoint is refused by name, when it is read rather than when the model is
built — so
Settings()still constructs with an empty environment, and a boot withoutPOSTGRES__HOSTfails saying so instead of dialling localhost. - Unset knobs are dropped, not forwarded as
None. The defaults live in the backend's own config object, never in a second copy on the settings model. - Secrets are
SecretStrand the assembled URL is one too wherever it carries a credential, so neither reaches a log by accident. The assembled value is a plain property rather than a serialized field:model_dump()on a settings root works even where a mounted backend was never configured, and no DSN lands in a dump. ssl=Trueverifies the server certificate —sslmode=verify-full,neo4j+s://,rediss://,https://. A deployment that wants weaker TLS leaves the flag off and configures the backend's own environment variables.
The URL-building models share forze.base.settings.EndpointSettings for the parts that are
URL grammar rather than backend knowledge — bracketing a bare IPv6 host, joining the port.
The scheme and the query parameters stay in each package, because that is the part that
actually differs.
forze.base.settings.RuntimeSettings is the same idea for the process itself: the argument
lists of bootstrap_logging and bootstrap_telemetry. See
Grafana stack.
Two packages ship no settings model, for the same reason both times: they are inbound,
so there is no connection to configure. fastapi and mcp serve requests; where they bind
is the deployment's uvicorn or transport concern, not the integration's.
Everything else has one, including the ones that are barely a connection at all: duckdb
is in-process, so DuckDbSettings carries the database path and the two resource limits
that decide whether a query is slow or the container is killed; SocketIOSettings carries
the Redis backplane — the URL, the channel, and whether this process publishes without
subscribing (build the URL from a RedisSettings.dsn, since integration packages do not
import each other); GcpKmsSettings is one emulator endpoint and one timeout, because
Google's credentials come from the ambient environment.