charts/formbricks
directory in the Formbricks repository.
Formbricks v5 self-hosting expects Hub to be part of the runtime. The chart handles that by default. Use the
migration guide before upgrading an existing 4.x deployment.
Prerequisites
Ensure you have the following before proceeding:- a running Kubernetes cluster
- Helm 3 installed locally
- a public hostname for
formbricks.webappUrl - a plan for PostgreSQL and Redis/Valkey, either in-cluster or managed externally
- an edge rate-limiting plan for the v5-covered routes: the chart’s Envoy bundle or an equivalent external edge solution
1. Install The Chart
1
Create A Minimal values.yaml
2
Install Formbricks
- the Formbricks application
- Formbricks Hub
- Cube
- PostgreSQL
- Redis
- generated Kubernetes Secrets
2. Configure Secrets And External Services
Using Generated Secrets
The default chart path keepssecret.enabled: true, which lets the chart generate the required application
secrets for you.
Adding An Enterprise License
There is no separateenterprise.enabled switch. Enterprise features are unlocked by a valid
ENTERPRISE_LICENSE_KEY. For a quick-start deployment that uses the chart-generated app Secret, set:
ENTERPRISE_LICENSE_KEY through your existing
Secret or ExternalSecret instead. The enterprise.licenseKey chart value only writes to the generated app Secret
when secret.enabled: true.
Using Managed PostgreSQL And Redis
For production workloads, many teams prefer managed services:Using External Secrets
If your cluster already uses an external secret manager, enableexternalSecret and point it at your existing
SecretStore. Ensure the resulting app secret exposes the values your deployment needs, including DATABASE_URL,
REDIS_URL, and HUB_API_KEY.
SpiceDB authorization
Formbricks v6 uses SpiceDB, maintained by AuthZed, as its authorization engine. Fresh chart installations enable a private, two-replica SpiceDB cluster andfully_consistent decisions by default. If the cluster already
has a compatible SpiceDB operator, keep the authorization runtime enabled but disable this release’s operator
installation:
authzed.operator.install: true installs the pinned operator, creates the cluster, and bootstraps a
dedicated spicedb database and login. Install only one operator in a Kubernetes cluster.
For managed PostgreSQL, create a separate SpiceDB database and login first. Store its connection URI and a
strong API token in a Kubernetes Secret using the keys datastore_uri and preshared_key, then configure:
authzed.mode: external, authzed.operator.install: false, authzed.endpoint: <host>:<port>, and
authzed.insecure: false when connecting
to an externally managed AuthZed endpoint. The external endpoint must serve TLS because the preshared token is
sent on every authenticated request. The application endpoint remains internal and uses plaintext gRPC by
default when the chart owns SpiceDB.
For an already-running v6 installation, Helm prints release-specific diagnostic commands that execute the
release-matched operator CLI inside a Formbricks pod:
helm upgrade or resuming GitOps.
The chart refuses an unacknowledged upgrade, disabled AuthZed, or weaker consistency. Follow
AuthZed Operations for ongoing operations and do not expose SpiceDB
through an Ingress.
3. v5-Specific Deployment Notes
Hub Is Mandatory
Formbricks v5 does not supporthub.enabled=false. Keep the default hub.enabled=true behavior in place.
Use hub.image.tag, hub.resources, and hub.existingSecret only when you need to pin or customize the Hub
deployment details.
Envoy Bundle Modes
The chart supports these edge patterns for the v5-covered routes:- Bundled Envoy controller and CRDs: set
envoy.enabled=true,envoy.controller.enabled=true, andenvoy.crds.enabled=true - Bundled Envoy controller with platform-managed CRDs: keep the controller enabled and set
envoy.crds.enabled=false - Existing cluster Envoy controller: set
envoy.enabled=true,envoy.controller.enabled=false,envoy.formbricks.gatewayClass.create=false, andenvoy.formbricks.gatewayClass.nameto the existing class - Equivalent external edge protection: keep using your platform’s own ingress or gateway layer if it already provides equivalent rate-limiting coverage
HelmRelease, also make the ownership boundary explicit:
envoy.controller.enabled: false, disable GatewayClass creation, and provide the existing
GatewayClass name. The controller dependency, including its CRDs, is disabled in this mode. In either mode, configure
envoy.formbricks.ingress or your platform ingress/load balancer so public traffic reaches the Envoy-managed
routes. If you use an equivalent external edge solution instead, verify that it covers every route in the
rate-limiting guide before exposing Formbricks.
Production Replicas And Disruption Budgets
For a production deployment that should remain available during a voluntary disruption, run at least two app replicas:maxUnavailable: 1 instead of
minAvailable and accept downtime during the eviction. Never set both fields; set the unused field to null in
your values file.
Two autoscaling defaults are easy to miss:
maxReplicas: 10can exceed what the node pool can hold. Each app pod requests 1 vCPU, so the ceiling needs about 10 allocatable vCPU for the app alone, on top of the platform reserve and the Hub, Cube and SpiceDB pods. A smaller pool leaves the extra replicasPending— an HPA does not lower its own ceiling.- The HPA scales on CPU and memory utilization only. Queue depth is not one of its metrics, so a job backlog can grow while both targets sit under their thresholds and no replica is added. Backlog-driven scaling needs a queue-depth metric published to the metrics API and added to the HPA yourself.
Cube
Cube is part of the baseline Formbricks v5 stack and is bundled with the chart by default (cube.enabled: true). To run an external Cube cluster instead:
- set
cube.enabled: falseto skip the bundled Cube deployment - point the app at your external endpoint via
deployment.env.CUBEJS_API_URL - supply
CUBEJS_API_SECRETviadeployment.envordeployment.envFromif you disable generated secrets
Optional Bundled Qwen/vLLM For AI
The Helm chart can optionally deploy a Formbricks-provided Qwen runtime through vLLM. This is disabled by default and requires GPU-capable Kubernetes nodes. To deploy Qwen/vLLM and automatically point the Formbricks app at the in-cluster OpenAI-compatible endpoint:llm.enabled: true, the chart renders the vLLM router and Qwen serving engine, then injects the required
AI_PROVIDER=openai-compatible app environment variables unless you override them in deployment.env.
If you want to deploy the bundled Qwen runtime without changing the Formbricks app AI configuration:
llm.enabled: false when you use Google Vertex, Azure, AWS Bedrock, or an externally managed
OpenAI-compatible endpoint. Configure those providers through deployment.env.
Optional AI Taxonomy Beta
The Helm chart can optionally deploy the standalone taxonomy service. This is disabled by default and does not force the bundled Qwen/vLLM runtime. To deploy taxonomy and reuse the bundled Qwen/vLLM runtime:TAXONOMY_SERVICE_URL, TAXONOMY_SERVICE_TOKEN, and HUB_INTERNAL_API_TOKEN into Hub API.
To use your own OpenAI-compatible LLM endpoint instead, keep llm.enabled: false and set the taxonomy LLM values:
taxonomy-llm-secret secret must contain TAXONOMY_LLM_API_KEY. If your endpoint does not enforce
authentication, store a non-empty dummy value.
To use Gemini on Vertex AI instead, keep llm.enabled: false, create a secret containing
TAXONOMY_GOOGLE_CLOUD_CREDENTIALS_JSON, and configure the Vertex provider:
TAXONOMY_GOOGLE_CLOUD_CREDENTIALS_JSON must be allowed to call Vertex AI for the selected
project and location.
After startup, run the authenticated preflight check from inside the taxonomy pod:
/health; /v1/preflight is for
operator validation and requires the internal taxonomy bearer token.
4. Upgrade The Deployment
Upgrading from v5 to v6
Use the v6 maintenance upgrade guide for the complete procedure, temporary Job template, and recovery instructions. Use only an upgrade pair listed as tested in the target release notes. Pin the target Formbricks image by digest and the matching chart version; preserve existing database, storage, and Secret bindings.1
Enter maintenance and take backups
Prepare private SpiceDB connectivity and complete its datastore migrations before the application upgrade.
Suspend GitOps reconciliation, autoscalers, image updaters, and schedules that could restart writers. Stop
all writers, including application replicas, Hub/workflow workers, running Jobs, and external integrations,
then wait for in-flight work and database transactions to finish. Take recoverable backups after writers
stop and keep maintenance active through preparation and access verification.
2
Prepare with the target v6 image
Run an explicit, temporary Kubernetes Job using the exact target image and the database/AuthZed environment
bindings that v6 will use, including The command validates configuration and SpiceDB health, runs application database migrations, prepares the
schema, drains the outbox, repairs relationships, and performs a separate final
AUTHZED_CONSISTENCY=fully_consistent. Run this command in that Job,
not in an existing v5 application pod:upgrade check. The flags
acknowledge prerequisites you have already verified; they do not stop workloads or take backups. Review
any non-empty schema mismatch using the guide’s guarded replacement procedure.3
Deploy only after preparation succeeds
Require the preparation Job to exit
0, then set authzed.migrationAcknowledged: true and deploy the same
image digest with the reviewed chart version. The Helm pre-upgrade hook verifies the prepared graph; it
does not run database migrations, apply the schema, or backfill relationships. Verify authorization and
outbox delivery before restoring controllers, workers, and public traffic as described in the guide.Later chart upgrades
For later v6 upgrades, follow the target release’s compatibility and maintenance notes. A changed canonical SpiceDB schema requires explicit preparation again; a previous migration acknowledgement does not bypass verification. For a compatible routine upgrade:- Hub remains enabled
HUB_API_KEYis present- your edge rate-limiting plan is in place
- any required
AI_*variables are added CUBEJS_API_SECRETis configured (the generated app secret supplies it by default; provide an external endpoint if you setcube.enabled: false)
5. Key Values
For the complete values surface, refer to the chart README in the repository:
charts/formbricks/README.md.