Skip to content

Deployment

Farcaster ships as a single, statically-linked Go binary. There is no sidecar, no runtime, and no required external service beyond the process itself — Postgres is optional but recommended for any durable deployment. The binary reads its entire configuration from the environment (Configuration reference).

The gateway will not boot without OIDC configuration — this is deliberate; there is no unauthenticated path to bring it up (see Auth & multi-tenancy).

Terminal window
FARCASTER_OIDC_ISSUER=https://issuer.example.com \
FARCASTER_OIDC_AUDIENCE=farcaster-gateway \
FARCASTER_DATABASE_URL=postgres://user:pass@db:5432/farcaster \
FARCASTER_KMS_KEY=$(openssl rand -hex 32) \
farcaster

By default it listens on :8080 (override with FARCASTER_ADDR).

Because the binary is static, a minimal base image is enough — there is nothing to install alongside it:

FROM gcr.io/distroless/static-debian12
COPY farcaster /usr/local/bin/farcaster
EXPOSE 8080
ENTRYPOINT ["farcaster"]

Inject configuration as environment variables from your platform’s secret store; do not bake secrets into the image (see KMS & secrets).

Two operational routes sit outside /v1 and require no authentication, so load balancers and orchestrators can probe them directly:

Route Use
GET /healthz Liveness/readiness — returns {"status":"ok"} once serving.
GET /version Build metadata (version + commit) — useful to confirm a rollout.

The gateway process is stateless — all durable state lives in Postgres — so you can run several replicas behind a load balancer and scale horizontally.

One caveat to size for: per-caller rate limiting is in-process, held in each instance’s memory rather than a shared store. Behind N replicas, a caller’s effective limit is up to N times the per-instance limit, since each instance meters independently. Account for this when setting limits, or pin a caller to an instance at the load balancer if you need a hard global bound.

On SIGINT/SIGTERM the gateway drains before exiting: it stops accepting new connections, gives in-flight HTTP requests (including streaming responses) up to 30 seconds to finish, then gives in-flight transactional proxy calls a further 30 seconds to record a terminal status. Give the container a termination grace period of at least 60 seconds so orchestrated rollouts don’t cut active invocations short.