Problem
The current quickstart workflow requires users to run database migrations manually using goose, which introduces several friction points:
- Go or goose must be installed locally — the docs suggest
go install github.com/pressly/goose/v3/cmd/goose@v3.26.0, but Go isn't listed as a prerequisite (#55)
- Migration files aren't available — the quickstart only provides
compose.yml, but the migrations/ directory lives in the full repo and is never downloaded (#56)
- River queue tables also need migrating — even if app migrations run, the API crash-loops because
river_leader and river_queue tables don't exist. This requires a separate river migrate-up command that isn't documented in the quickstart
make init-db is referenced but no Makefile is provided in the quickstart flow (#54)
The net result: docker compose up alone does not produce a working system. The API fails with vector type not found or relation "river_queue" does not exist errors.
Proposed solution
Add a one-shot migration init container to compose.yml that runs before the Hub API starts. The ghcr.io/formbricks/hub:latest image already bundles goose, river, and the migration SQL files, so no additional tooling or files are needed on the host.
hub-migrate:
image: ghcr.io/formbricks/hub:latest
restart: "no"
entrypoint: ["sh", "-c"]
command:
[
'if [ -x /usr/local/bin/goose ] && [ -x /usr/local/bin/river ]; then /usr/local/bin/goose -dir /app/migrations postgres "$$DATABASE_URL" up && /usr/local/bin/river migrate-up --database-url "$$DATABASE_URL"; else echo ''Migration tools (goose/river) not in image.''; exit 1; fi',
]
environment:
DATABASE_URL: postgresql://formbricks:${POSTGRES_PASSWORD:-formbricks_dev}@postgres:5432/hub?sslmode=disable
depends_on:
postgres:
condition: service_healthy
networks:
- formbricks_hub
The hub service then depends on it:
hub:
depends_on:
postgres:
condition: service_healthy
hub-migrate:
condition: service_completed_successfully
Why this approach over a Makefile
|
Migration container |
Makefile |
| Extra host dependencies |
None |
Go (or standalone goose) |
| Migration files needed locally |
No (bundled in image) |
Yes (must clone repo) |
| Setup command |
docker compose up -d |
make init-db && docker compose up -d |
| Target audience fit |
Quickstart / Docker users |
Developers working on the Go codebase |
For the quickstart audience (deploying via Docker), a single docker compose up -d that handles everything is the ideal experience. The Makefile remains useful for local development but shouldn't be a prerequisite for Docker-based deployment.
Additional note
$DATABASE_URL in the command must be escaped as $$DATABASE_URL — otherwise Docker Compose interpolates it with the host's value (typically empty) instead of letting the container's shell resolve it at runtime.
Verified
This approach was tested end-to-end. All 6 app migrations and 6 River queue migrations apply successfully, and the Hub API starts cleanly with a healthy /health endpoint.
Related issues
Problem
The current quickstart workflow requires users to run database migrations manually using
goose, which introduces several friction points:go install github.com/pressly/goose/v3/cmd/goose@v3.26.0, but Go isn't listed as a prerequisite (#55)compose.yml, but themigrations/directory lives in the full repo and is never downloaded (#56)river_leaderandriver_queuetables don't exist. This requires a separateriver migrate-upcommand that isn't documented in the quickstartmake init-dbis referenced but no Makefile is provided in the quickstart flow (#54)The net result:
docker compose upalone does not produce a working system. The API fails withvector type not foundorrelation "river_queue" does not existerrors.Proposed solution
Add a one-shot migration init container to
compose.ymlthat runs before the Hub API starts. Theghcr.io/formbricks/hub:latestimage already bundlesgoose,river, and the migration SQL files, so no additional tooling or files are needed on the host.The
hubservice then depends on it:Why this approach over a Makefile
docker compose up -dmake init-db && docker compose up -dFor the quickstart audience (deploying via Docker), a single
docker compose up -dthat handles everything is the ideal experience. The Makefile remains useful for local development but shouldn't be a prerequisite for Docker-based deployment.Additional note
$DATABASE_URLin the command must be escaped as$$DATABASE_URL— otherwise Docker Compose interpolates it with the host's value (typically empty) instead of letting the container's shell resolve it at runtime.Verified
This approach was tested end-to-end. All 6 app migrations and 6 River queue migrations apply successfully, and the Hub API starts cleanly with a healthy
/healthendpoint.Related issues
make init-dbbut no Makefile exists in the repo #54 — Docs referencemake init-dbbut no Makefile in quickstart