Part 8 · 1 chapters · ~8 min

Pairing Tables by Runtime

The usual production stack for Node, Python, Go, Rust, Rails, Java, .NET and Elixir at one service, ten services and a hundred, with the reason each pairing exists.

11

What each runtime is paired with

runtime1 service10 services100 services
NodeFastify/Express on a PaaS, Postgres, Rediscontainers, BullMQ, PgBouncer, OTel SDK, Nginx/ALBKubernetes, Kafka, mesh sidecars, API gateway, Vault
PythonDjango + Gunicorn + Nginx, Postgres, Celery + RedisUvicorn/ASGI, PgBouncer, Celery beat, Sentry, OTelKubernetes, Kafka, RabbitMQ, mesh, Vault
Goone binary, systemd or a PaaS, Postgrescontainers, gRPC, Prometheus, NATS or RedisKubernetes, Envoy/Istio, Kafka, Consul or k8s discovery
RustAxum binary behind Caddycontainers, Tokio tuning, OTel, Redisoften the hot-path service inside a Go or Java platform
RailsPuma + Nginx (or Kamal), Postgres, Solid Queue or SidekiqPgBouncer, Redis, Sidekiq, Sentry, CDN for assetsKubernetes, Kafka, modular monolith split into services slowly
JavaSpring Boot fat jar, Postgres, HikariCPSpring Cloud Config, Eureka or k8s, Kafka, Micrometer, OTel agentKubernetes, Istio sidecars, Kafka, Vault, Quarkus native for small services
.NETASP.NET Core on Kestrel behind a proxy, SQL Server or Postgrescontainers, MassTransit + RabbitMQ, OTelKubernetes, Azure Service Bus, Dapr or a mesh
ElixirPhoenix release, Postgres, Obanlibcluster for BEAM clustering, Phoenix PubSubKubernetes, Kafka via Broadway; fewer external pieces needed

Each pairing exists to cover a weakness: Python and Ruby need app servers and workers because of the GIL/GVL and their request models; the JVM's heavy startup pushes toward fewer, larger instances (or native images); Go's single binary needs little; Elixir's BEAM provides supervision and clustering that other stacks buy from infrastructure.