
Deploying a FHIR server on Kubernetes in 2026 involves a mix of standard cloud-native patterns and FHIR-specific considerations. The five patterns below cover most production deployments.
1. StatefulSet with persistent volume for FHIR server + Postgres. The FHIR server itself is often stateless (state lives in Postgres), but Postgres is stateful. Use StatefulSet for Postgres with a dedicated PersistentVolumeClaim.
2. Horizontal Pod Autoscaler on request-rate. Scale FHIR server replicas on CPU and request-rate metrics. HAPI FHIR, Aidbox FHIR server, and Medplum all support horizontal scaling; the JPA-backed HAPI needs careful Postgres connection pooling.
3. Sidecar terminology server co-location. Deploy terminology server as a sidecar or as a separate deployment in the same namespace with a service discovery mechanism. Ontoserver runs cleanly this way.
4. Bulk data export storage via CSI. Bulk data `$export` writes NDJSON to storage. Mount an S3-compatible CSI volume; lifecycle rules handle cleanup.
5. Ingress with TLS + rate limiting. NGINX Ingress or Envoy for TLS termination, rate limiting per token/scope, and CORS handling. SMART launch domains whitelisted explicitly.
Resource sizing (mid-2026, moderate ambulatory clinic)
| Component | CPU | Memory | Storage |
|---|---|---|---|
| FHIR server (2 replicas) | 4 vCPU | 8 GB | ephemeral |
| Postgres | 8 vCPU | 32 GB | 500 GB SSD |
| Terminology server | 2 vCPU | 8 GB | 20 GB |
| Redis (cache) | 2 vCPU | 4 GB | ephemeral |
| Bulk export storage | N/A | N/A | 100 GB S3 |
Monitoring stack
Prometheus + Grafana is the standard. Alert on: request-rate anomalies, Postgres connection pool saturation, bulk export queue depth, terminology server latency, and $validate pass rate.
Kubernetes FHIR deployment is straightforward with the patterns above. The pitfalls are usually Postgres tuning, not Kubernetes itself.