Quick Start Guide
Get Formbricks Hub running locally in minutes.
Prerequisites
Section titled “Prerequisites”- Docker and Docker Compose: Install Docker Desktop
Installation
Section titled “Installation”Option 1: Docker Compose (Recommended)
Section titled “Option 1: Docker Compose (Recommended)”The easiest way to run Formbricks Hub with all dependencies.
1. Create the Docker Compose File
Section titled “1. Create the Docker Compose File”Create a new directory:
mkdir formbricks-hub && cd formbricks-hubCreate compose.yml:
services: postgres: image: pgvector/pgvector:pg18 container_name: formbricks_hub_postgres restart: unless-stopped environment: POSTGRES_USER: formbricks POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-formbricks_dev} POSTGRES_DB: hub ports: - "${POSTGRES_PORT:-5432}:5432" volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U formbricks -d hub"] interval: 10s timeout: 5s retries: 5 networks: - formbricks_hub command: > postgres -c shared_preload_libraries=vector
hub-migrate: image: ghcr.io/formbricks/hub:${HUB_IMAGE_TAG:-latest} container_name: formbricks_hub_migrate restart: "no" depends_on: postgres: condition: service_healthy environment: DATABASE_URL: postgresql://formbricks:${POSTGRES_PASSWORD:-formbricks_dev}@postgres:5432/hub?sslmode=disable entrypoint: ["/bin/sh", "-c"] command: > /usr/local/bin/goose -dir /app/migrations postgres "$$DATABASE_URL" up && /usr/local/bin/river migrate-up --database-url "$$DATABASE_URL" networks: - formbricks_hub
hub: image: ghcr.io/formbricks/hub:${HUB_IMAGE_TAG:-latest} container_name: formbricks_hub_api restart: unless-stopped depends_on: postgres: condition: service_healthy hub-migrate: condition: service_completed_successfully environment: DATABASE_URL: postgresql://formbricks:${POSTGRES_PASSWORD:-formbricks_dev}@postgres:5432/hub?sslmode=disable API_KEY: ${API_KEY:-} PORT: 8080 PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-} LOG_LEVEL: ${LOG_LEVEL:-info} ports: - "${HUB_PORT:-8080}:8080" healthcheck: test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health", ] interval: 30s timeout: 5s retries: 3 start_period: 10s networks: - formbricks_hub
hub-worker: image: ghcr.io/formbricks/hub:${HUB_IMAGE_TAG:-latest} container_name: formbricks_hub_worker restart: unless-stopped depends_on: postgres: condition: service_healthy hub-migrate: condition: service_completed_successfully environment: DATABASE_URL: postgresql://formbricks:${POSTGRES_PASSWORD:-formbricks_dev}@postgres:5432/hub?sslmode=disable LOG_LEVEL: ${LOG_LEVEL:-info} entrypoint: ["/app/hub-worker"] healthcheck: disable: true networks: - formbricks_hub
volumes: postgres_data: driver: local
networks: formbricks_hub: driver: bridge2. Configure Environment Variables
Section titled “2. Configure Environment Variables”Create a .env file in the same directory:
# Required: Secure your PostgreSQL databasePOSTGRES_PASSWORD=your_secure_postgres_password_here
# Required: API authentication keyAPI_KEY=your_secure_api_key_here
# Optional: Host ports and Hub image tagHUB_PORT=8080POSTGRES_PORT=5432HUB_IMAGE_TAG=latestLOG_LEVEL=info
# Optional: Public URL advertised in /openapi.yaml and /openapi.json# Set this for production behind ingress, TLS termination, or a path prefix.PUBLIC_BASE_URL=# For POSTGRES_PASSWORDopenssl rand -base64 32
# For API_KEYopenssl rand -base64 323. Start Hub
Section titled “3. Start Hub”docker compose up -dThis will:
- Start PostgreSQL with persistent storage
- Run database migrations and create River tables with the one-shot
hub-migrateservice - Pull the latest Formbricks Hub image from GitHub Container Registry
- Start the Hub API on port 8080
- Start the Hub worker for asynchronous jobs
Migrations are managed with goose and River. The published Hub image includes goose, river, and /app/migrations, so Docker Compose can migrate the database without local Go, goose, river, or migration files.
4. Verify Installation
Section titled “4. Verify Installation”Check that the services are running:
docker compose ps --allExpected output:
NAME STATUS PORTSformbricks_hub_api Up (healthy) 0.0.0.0:8080->8080/tcpformbricks_hub_migrate Exited (0)formbricks_hub_postgres Up (healthy) 0.0.0.0:5432->5432/tcpformbricks_hub_worker UpTest the health endpoint:
curl http://localhost:8080/healthExpected response:
OKCheck that the runtime OpenAPI spec is available without authentication:
curl http://localhost:8080/openapi.jsonExpected response: an OpenAPI JSON document with Hub API metadata and paths.
Option 2: Docker Run (Minimal)
Section titled “Option 2: Docker Run (Minimal)”If you have an existing PostgreSQL instance, run migrations first:
docker run --rm \ -e DATABASE_URL="postgresql://user:password@host:5432/hub?sslmode=disable" \ --entrypoint /bin/sh \ ghcr.io/formbricks/hub:latest \ -c 'goose -dir /app/migrations postgres "$DATABASE_URL" up && river migrate-up --database-url "$DATABASE_URL"'The published Hub image includes goose, river, and /app/migrations, so
this applies both Hub database migrations and River queue migrations without
local Go, goose, river, or migration files.
Then run the Hub API:
docker run -d \ --name formbricks-hub \ -p 8080:8080 \ -e DATABASE_URL="postgresql://user:password@host:5432/hub?sslmode=disable" \ -e API_KEY="your-secret-key" \ -e LOG_LEVEL="info" \ ghcr.io/formbricks/hub:latestMaking Your First API Call
Section titled “Making Your First API Call”1. Create a Feedback Record
Section titled “1. Create a Feedback Record”curl -X POST http://localhost:8080/v1/feedback-records \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your_secure_api_key_here" \ -d '{ "tenant_id": "org-123", "submission_id": "subm-my-first-survey-001", "source_type": "survey", "source_id": "my-first-survey", "field_id": "q1", "field_label": "How satisfied are you?", "field_type": "rating", "value_number": 5, "metadata": { "country": "US", "device": "desktop" } }'Expected response:
{ "id": "01932c8a-8b9e-7000-8000-000000000001", "tenant_id": "org-123", "submission_id": "subm-my-first-survey-001", "collected_at": "2025-10-20T12:34:56Z", "created_at": "2025-10-20T12:34:56Z", "updated_at": "2025-10-20T12:34:56Z", "source_type": "survey", "source_id": "my-first-survey", "field_id": "q1", "field_type": "rating", "value_number": 5, "metadata": { "country": "US", "device": "desktop" }}2. Create a Text Feedback Record
Section titled “2. Create a Text Feedback Record”curl -X POST http://localhost:8080/v1/feedback-records \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your_secure_api_key_here" \ -d '{ "tenant_id": "org-123", "submission_id": "subm-my-first-survey-001", "source_type": "survey", "source_id": "my-first-survey", "field_id": "q2", "field_label": "What can we improve?", "field_type": "text", "value_text": "The checkout process could be simplified!" }'3. Query Feedback Records
Section titled “3. Query Feedback Records”curl "http://localhost:8080/v1/feedback-records?tenant_id=org-123&limit=10" \ -H "Authorization: Bearer your_secure_api_key_here"Response:
{ "data": [ { "id": "01932c8a-8b9e-7000-8000-000000000001", "tenant_id": "org-123", "submission_id": "subm-my-first-survey-001", "collected_at": "2025-10-20T12:34:56Z", "created_at": "2025-10-20T12:34:56Z", "updated_at": "2025-10-20T12:34:56Z", "source_type": "survey", "source_id": "my-first-survey", "field_id": "q1", "field_type": "rating", "value_number": 5 } ], "limit": 10}Configuration
Section titled “Configuration”Environment Variables
Section titled “Environment Variables”| Variable | Required | Default | Description |
|---|---|---|---|
DATABASE_URL | No | postgres://postgres:postgres@localhost:5432/test_db?sslmode=disable | PostgreSQL connection string |
API_KEY | Yes | - | API authentication key |
PORT | No | 8080 | HTTP server port |
PUBLIC_BASE_URL | No | - | Public API root advertised in runtime OpenAPI specs |
LOG_LEVEL | No | info | Log level (debug, info, warn, error) |
In the Docker Compose example above, use HUB_PORT and POSTGRES_PORT to change
host ports without changing the ports used inside the containers.
See full environment variable reference ->
Database Connection String Format
Section titled “Database Connection String Format”postgresql://username:password@host:port/database?sslmode=disableFor Docker Compose (services in same network):
postgresql://formbricks:password@postgres:5432/hub?sslmode=disableFor external PostgreSQL:
postgresql://user:pass@db.example.com:5432/hub?sslmode=requireManaging the Service
Section titled “Managing the Service”View Logs
Section titled “View Logs”# All servicesdocker compose logs -f
# Just the Hub APIdocker compose logs -f hub
# Just the Hub workerdocker compose logs -f hub-worker
# Just PostgreSQLdocker compose logs -f postgresStop Services
Section titled “Stop Services”docker compose downStop and Remove Data
Section titled “Stop and Remove Data”docker compose down -vRestart Services
Section titled “Restart Services”docker compose restartUpdate to Latest Version
Section titled “Update to Latest Version”docker compose pulldocker compose stop hub hub-workerdocker compose up --force-recreate hub-migratedocker compose up -dWhen updating Hub images, recreate hub-migrate so goose and River migrations
from the new image are applied before the API and worker continue running.
Next Steps
Section titled “Next Steps”- Data Model - Understand the feedback record structure
- Authentication - Learn about API security
- Connect Hub to AI Clients via MCP - Use Hub from MCP-capable AI clients
- API Reference - Explore all endpoints
- Environment Variables - Configure your deployment
Troubleshooting
Section titled “Troubleshooting”Port Already in Use
Section titled “Port Already in Use”If port 8080 or 5432 is occupied:
# Change ports in .envHUB_PORT=8081POSTGRES_PORT=5433Or modify the port mapping in compose.yml:
ports: - "${HUB_PORT:-8080}:8080" # Host:ContainerContainer Fails to Start
Section titled “Container Fails to Start”Check the logs for errors:
docker compose logs hubCommon issues:
- Database not ready: Wait for PostgreSQL healthcheck to pass
- Invalid API key: Ensure
API_KEYis set in.env - Database connection failed: Check
DATABASE_URLformat
Database Connection Failed
Section titled “Database Connection Failed”Verify PostgreSQL is running:
docker compose ps postgresIf unhealthy, check PostgreSQL logs:
docker compose logs postgresHealth Check Failing
Section titled “Health Check Failing”Check if the service is listening:
docker exec formbricks_hub_api wget -O- http://localhost:8080/healthCannot Pull Docker Image
Section titled “Cannot Pull Docker Image”Ensure you have access to GitHub Container Registry:
docker pull ghcr.io/formbricks/hub:latestIf authentication is required:
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdinData Not Persisting
Section titled “Data Not Persisting”Verify the volume is mounted:
docker volume ls | grep postgres_datadocker volume inspect formbricks-hub_postgres_dataGetting Help
Section titled “Getting Help”- GitHub Discussions: Ask questions and share ideas
- GitHub Issues: Report bugs or request features
- API Reference: Interactive documentation