Deploy Formbricks

Self-host Formbricks — surveys, NPS, CSAT, responses stay in your Postgres

Deploy Formbricks

Just deployed

/var/lib/postgresql/data

Just deployed

/data

hub-worker

formbricks/hub

Just deployed

Just deployed

formbricks-uploads

Bucket

Just deployed

Deploy and Host Formbricks on Railway

Formbricks is an open-source survey and experience management platform — a self-hosted alternative to Typeform, Qualtrics and SurveyMonkey. Build link surveys, in-app and website surveys, NPS and CSAT programmes, and read the results with no per-response ceiling. This template deploys the full v5 stack, Hub included, with every secret generated once and held stable, so the setup wizard is the first thing you see rather than a migration error.

What This Template Deploys

ServicePurpose
formbricksNext.js web app on port 3000. Public domain, health-checked at /health.
PostgresSurveys, responses, contacts, users and organisations. Volume attached.
RedisCache, rate limiting and audit behaviour.
hub-apiFormbricks Hub API. Mandatory in v5, not optional.
hub-workerHub background processing. No public route.
cubeSemantic layer behind response analytics.

Everything talks over Railway's private network and only the web app takes a public domain. Postgres is the sole source of truth — the app and Hub services are replaceable, which is why no volume hangs off them.

About Hosting

Formbricks v5 is a materially different deployment from v4, and most self-hosting guidance online still describes v4. That gap is where the failures live.

A three-service stack is a v4 stack. Formbricks Hub became mandatory for self-hosted v5. Deploy the old app-plus-Postgres-plus-Redis shape, let it pull a latest tag that now resolves to v5, and the app starts but cannot do the work the Hub handles. Match architecture to version and pin the tag — Formbricks' own README template broke on this, with users hitting missing-tag errors on both the app and database image.

Five secrets, all of which must survive redeploys. NEXTAUTH_SECRET, ENCRYPTION_KEY, CRON_SECRET, HUB_API_KEY and CUBEJS_API_SECRET are each 32-byte hex, and they fail differently: a changed ENCRYPTION_KEY makes 2FA secrets and stored integration credentials undecryptable, while a changed HUB_API_KEY silently severs the app from the Hub.

Without SMTP you have no way back into your own instance. The setup wizard creates the first admin account without email, so the deploy looks complete. Password reset, verification, invitations and notifications all need SMTP, and you learn that the day someone is locked out. Add SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD and MAIL_FROM before inviting anyone.

Behind Railway's proxy, every request looks like one IP. Formbricks reads the client address from forwarded headers, and TRUSTED_PROXY_HOP_COUNT says how many proxies to trust. Leave it unset and rate limiting, audit logs and response de-duplication all attribute traffic to the proxy rather than real visitors — a correctness problem that never announces itself.

File-upload answers need object storage. Questions that accept files write to local storage by default, which on Railway means a container layer replaced on the next deploy. Configure object storage before publishing a survey with a file question, not after the uploads vanish.

Typical cost: ~$25–40/month for the full six-service v5 stack at $10/GB/month RAM, $20/vCPU/month CPU and $0.15/GB/month volumes. Formbricks itself is free and open source, with no cap on responses.

How It Compares

Formbricks (self-hosted)TypeformQualtricsGoogle Forms
Response limitsNonePlan tierPlan tierNone
Data locationYour PostgresVendorVendorGoogle
Self-hostableYesNoNoNo

The honest edge: Typeform is still the nicer authoring experience and Google Forms is free and needs nothing from you, so for an occasional public survey neither is worth replacing. Formbricks earns its keep when responses are personal data you cannot hand a vendor, when per-response pricing has started shaping what you are willing to ask, or when you want in-app surveys triggered on behaviour rather than a link emailed out.

Deploy in Under 5 Minutes

  1. Click Deploy and pick a workspace. All six services come up with the five secrets generated and the URL variables pointed at your Railway domain.
  2. Wait out the first-boot migration window. The app answers /health only once Prisma finishes, so give it a minute before assuming failure.
  3. Open the public domain. Formbricks redirects to its setup wizard, where you create the first admin account and your organisation.
  4. Add SMTP variables now, while you remember. Without them nobody can reset a password or accept an invitation.
  5. Create a survey from a template, publish it, and submit one response to confirm the path through Hub and Cube works end to end.

Verify before you rely on it: redeploy the whole project, then open that response again. If it is still there and still renders analytics, Postgres, the Hub link and your secrets are all intact.

Common Use Cases

  • In-app and website surveys — trigger NPS or CSAT on user behaviour through the JS widget rather than emailing a link and hoping.
  • Privacy-constrained feedback — collect open text, emails and account-linked scores where responses are personal data that must stay on your infrastructure.
  • Unlimited-volume research — run continuous feedback programmes without per-response pricing shaping what you ask.

Configuration

VariableRequiredDescription
WEBAPP_URL, NEXTAUTH_URLRequiredPublic HTTPS domain. Links, redirects and the widget are built from these.
ENCRYPTION_KEYGeneratedEncrypts 2FA secrets and stored integration credentials. Never rotate.
HUB_API_KEYGeneratedAuthenticates the app to the Hub. A mismatch severs them silently.
CUBEJS_API_SECRETGeneratedSigns requests to the Cube analytics service.
DATABASE_URLAutoReference variable on the private Postgres hostname.
TRUSTED_PROXY_HOP_COUNTRequiredProxies in front of the app. A wrong value breaks rate limiting and audit logs.
SMTP_*, MAIL_FROMRecommendedPassword reset, verification, invitations, notifications.

Never rotate ENCRYPTION_KEY on a populated database. Two-factor secrets and stored integration credentials are encrypted with it and cannot be recovered without it.

Set SMTP before inviting anyone. The setup wizard works without it, which is what makes this easy to walk into — the first person needing a password reset is the one who finds out.

Dependencies for Formbricks Hosting

  • Railway account — ~$25–40/month for the full v5 stack; less if you scale the Hub worker and Cube down.
  • Bundled services — Postgres for durable data, Redis for cache and rate limiting, the Hub API and worker, Cube for analytics. All wired by the template.
  • Volume — on Postgres only. Formbricks is stateless once uploads go to object storage.
  • Optional but expected — SMTP for account emails, object storage for file uploads, OAuth providers for SSO.

Deployment Dependencies

Implementation Details

The web application runs the official image on a pinned tag rather than latest, listening on 3000 behind the Railway domain with /health as the health-check target. Every image in the stack is pinned, which matters more here than usual: Formbricks' own README template referenced tags that did not exist, and self-hosters hit missing-tag errors on both the app and database image before deployment began.

The v5 topology is the part worth understanding. The web app authors and serves surveys; the Hub API and worker handle processing that used to live in the monolith; Cube provides the semantic layer behind analytics. They authenticate with HUB_API_KEY and CUBEJS_API_SECRET, generated once and referenced across services rather than typed twice. Prisma applies migrations on first boot, which is why the health-check window needs room.

For backups, Postgres holds everything — surveys, responses, contacts, organisations, settings. Dump it on a schedule and store ENCRYPTION_KEY separately, because a restored database without it holds integration credentials and 2FA secrets nobody can read. If you enable file-upload questions, back up the object storage bucket too; those files are not in Postgres.

Frequently Asked Questions

Why six services instead of three? Formbricks Hub is mandatory for self-hosted v5. Older three-service templates describe v4, and a v5 image in that shape leaves the app without the Hub it expects.

Can I skip SMTP? For a single admin, briefly. Password reset, verification, invitations and notifications all need it, and adding it after someone is locked out is not a good afternoon.

Where do my responses live? In your Postgres, on your Railway volume — open text, emails and account-linked scores never leave infrastructure you control.

Why are rate limits and audit logs attributing everything to one IP? TRUSTED_PROXY_HOP_COUNT is unset or wrong, so Formbricks is reading Railway's proxy address instead of the real client.

Why Deploy Formbricks on Railway?

Railway is a singular platform to deploy your infrastructure stack. Railway will host your infrastructure so you don't have to deal with configuration, while allowing you to vertically and horizontally scale it.

By deploying Formbricks on Railway you get the v5 stack as it is meant to run — the Hub deployed rather than assumed, five secrets generated once and held stable, proxy hop count set so rate limits mean something, and pinned images instead of a tag that moves under you.


Template Content

More templates in this category

View Template
NEW
Typesense PHP
official PHP client against Railway

onepush
0
View Template
Typesense vs Meilisearch
self-hosted Typesense vs Meilisearch

onepush
0
View Template
Matomo Analytics + MariaDB
Privacy-friendly analytics with MariaDB and persistent volumes.

leodev
1