We do not build whole products in Go by default. We build the parts that have to be predictable at three in the morning: the ingestion endpoint taking a thousand events a second, the gateway in front of a payment flow, the worker that must never fall behind.
Why it suits those jobs
Concurrency is part of the language rather than a library choice. Memory behaviour is easy to reason about. The binary is a single file with no runtime to install, which makes the container small and the deploy dull — and dull is the goal for the component everything else depends on.
How we scope it
A Go service in one of our systems is deliberately narrow. It does one job, owns one data path, and exposes a contract the rest of the product can rely on. If it starts growing an admin interface and a template engine, it has drifted and we move that part back to Node or Python.
Operability comes with it
Structured logs, health endpoints, metrics for the queue depth and the latency percentiles that actually matter, and graceful shutdown so a deploy does not drop work in flight. None of that is optional on a service whose whole reason to exist is reliability.
The cost we tell clients about
A second backend language means a second set of build tooling, a second dependency policy and a smaller pool of people who can change it. On a small product that cost outweighs the benefit, and we will say so. On a system where a slow path is a lost customer, it pays for itself in the first incident it prevents.
Deployed the same way as everything else — see Kubernetes and Docker and CI/CD pipelines.