Go as the server language¶
Context and Problem Statement¶
The server holds many long-lived WebSocket connections, filters every event per recipient, writes to PostgreSQL and runs on a Mac and in Linux containers (linux/amd64, linux/arm64). OpenAPI and AsyncAPI are normative, server stubs are generated (B2). Which language does the server use?
Decision Drivers¶
- Concurrency for many connections in one process, without an external broadcast service.
- A static binary for small multi-arch images.
- Mature libraries for PostgreSQL, WebSocket, WebAuthn, background jobs and OpenTelemetry.
- Code generation from OpenAPI 3.1.
- A language that many build sessions write safely and uniformly (formatter, vet, static types).
Considered Options¶
- Go
- Python with FastAPI
- Elixir with Phoenix
Decision Outcome¶
Chosen option: "Go", because it offers concurrency and static types in one binary and has a
maintained library for every layer needed. go.mod sets the older maintained line as the
go directive; builds use the current version (R-Stack).
Consequences¶
- Good, because goroutines per connection and a hub in the process carry the fan-out without a broker.
- Good, because one binary with roles fits into a small image (B12).
- Good, because
gofmt,go vetand static types enforce uniform code across many sessions. - Bad, because the SDK and the Hermes adapter stay in Python; the team maintains two languages plus Dart.
- Bad, because Go versions are only maintained until two newer ones have been released; upgrades are mandatory (Renovate, ADR 0041).
Confirmation¶
make typecheckandmake testbuild and testservices/serverwithgo(gate).- The
godirective inservices/server/go.modnames the older maintained Go line, thetoolchaindirective the built version. New Go versions arrive as a Renovate proposal (ADR 0041); the review holds the rule. There is no gate check for this, because "maintained" cannot be determined without network access. - The build produces images for linux/amd64 and linux/arm64 (18-release.md).
Pros and Cons of the Options¶
Go¶
- Good, because Go 1.27 and 1.26 are maintained; go1.27.2 of 2026-10-08 is current. [verified, Q1]
- Good, because the standard ServeMux supports method patterns and wildcards since Go 1.22. [verified, Q2]
- Good, because coder/websocket (ISC) uses contexts throughout and allows concurrent writes. [verified, Q3]
- Good, because the OpenTelemetry SDK for Go lists traces and metrics as stable. [verified, Q4]
- Good, because oapi-codegen generates servers for
net/httpwith a strict interface. [verified, Q7] - Bad, because logs in the OTel SDK for Go are only a "Release candidate". [verified, Q4]
Python with FastAPI¶
- Good, because the SDK and the Hermes adapter are already Python.
- Bad, because according to the docs the WebSocket broadcast works only in the memory of one process; for several workers they refer to an external broadcast service. [verified, Q5]
- Bad, because a Python service is not a static binary; images and dependencies become larger. [derived]
Elixir with Phoenix¶
- Good, because Phoenix Presence replicates process information in the cluster without a central point. [verified, Q6]
- Bad, because another language and runtime is added, for which less exists in the team and in the tools (code generation from OpenAPI, license gates). [derived]
More Information¶
Sources, retrieved 2026-10-10:
- Q1 https://go.dev/doc/devel/release
- Q2 https://go.dev/blog/routing-enhancements
- Q3 https://github.com/coder/websocket (v1.8.15)
- Q4 https://opentelemetry.io/docs/languages/go/
- Q5 https://fastapi.tiangolo.com/advanced/websockets/
- Q6 https://phoenix.hexdocs.pm/presence.html
- Q7 https://github.com/oapi-codegen/oapi-codegen (v2.8.0)
Planning basis B2, R-Stack. 02-architecture.md, sections 5 and 6.