Not Everything Belongs in FHIR: A HAPI FHIR Server on Kubernetes for Millions of Observations

Home » Success stories » HAPI FHIR on Kubernetes Case Study

Not Everything Belongs in FHIR: A HAPI FHIR Server on Kubernetes for Millions of Observations

A HealthTech company running remote patient monitoring and virtual care needed one clinical data model that could absorb millions of device Observations without slowing the APIs its clinicians rely on. Valletta's backend, FHIR and platform engineers built it on a HAPI FHIR server (HL7 FHIR R4, version 4.0.1) on Kubernetes, with a backend layer in front, analytics on a separate path, and a firm rule about what never becomes a FHIR resource.


Key Takeaways

  • HL7 FHIR R4 on a HAPI FHIR server is the canonical clinical model, not just an integration API
  • At least fifteen FHIR resource types, millions of Observations; application state deliberately stays outside FHIR
  • Analytics runs on a separate layer fed from FHIR data, so heavy queries never compete with production clinical APIs
  • Frontends never call FHIR directly; a backend layer owns auth, orchestration and access control, and Subscriptions drive alerting

The client is a HealthTech company running a cloud platform for remote patient monitoring and virtual care. Valletta's engineers, embedded in the product team, owned the clinical data model, the backend integration with FHIR and the Kubernetes architecture under it. For confidentiality we describe the engagement without naming the company or the people involved.

The Challenge: A Clinical Model That Had to Survive Its Own Data Volume

A hospital record grows with visits; a monitoring platform grows with every reading. One patient reporting oxygen saturation, heart rate, blood pressure and temperature generates many Observation resources a day, and a growing population turns that into millions of clinical records. The clinical data platform sat under ten healthcare workflows, from device ingestion to dashboards, alerting, consultations, analytics and care pathways. Five problems followed:

  • Interoperability: clinical entities as correct FHIR resources with meaningful relationships, not convenient application tables
  • Volume: millions of Observations put indexing, query patterns, retention and performance on the critical path
  • Analytics: population-level queries behave nothing like transactional reads and must not slow production APIs
  • Change and availability: workflows evolve, and monitoring cannot tolerate downtime
  • Modeling: where FHIR should stop and the application should begin
Operational and analytical workloads, separated: patient and clinician applications call a backend layer for authentication, orchestration, validation and access control, which reads and writes a HAPI FHIR R4 server for operational clinical APIs; FHIR Subscriptions notify downstream services such as alerting, while a separate path takes FHIR data through data processing into analytics services, reports and dashboards
Operational and analytical workloads, separated: applications reach HAPI FHIR R4 only through the backend layer, Subscriptions feed downstream services such as alerting, and analytics runs on its own path from FHIR data to reports and dashboards.

The Approach: FHIR as the Canonical Model, Not as the Whole Application

The first decision: for a significant part of the platform, HL7 FHIR R4 is the canonical clinical data model. Clinical information lives as standard FHIR resources, not proprietary structures, so every service speaks the same vocabulary for a patient, a measurement or an encounter. The second decision is the guardrail on the first: an application layer and a clinical-data layer, deliberately split. The HAPI FHIR server stays focused on standardized clinical data; everything that is really application behaviour lives in a backend in front of it. Three tests decided what became a FHIR resource: genuine clinical meaning, a need to interoperate, or membership of the standardized healthcare domain. The same engineers owned the Kubernetes architecture underneath (Valletta's DevOps and platform engineering practice): a well-modeled FHIR server deployed as a snowflake is still a production risk.

The Solution: A HAPI FHIR Server Behind a Backend Layer, on Kubernetes

The clinical resource model: at least fifteen FHIR R4 resource types

Patient is the hub: measurements, devices, appointments, encounters and alerts all reference it, which makes the patient-scoped query the natural unit of work for the operational API.

FHIR R4 resourceRole in the platform
PatientThe person receiving care; the reference everything else points to
PractitionerHealthcare professionals using the platform
PractitionerRoleA practitioner's role in an organization; access can depend on role, not only person
OrganizationHealthcare organizations and their structures
CareTeamThe practitioners monitoring or caring for a patient
AppointmentPlanned consultations, including virtual ones
EncounterClinical interactions that actually took place
ObservationEvery device-generated measurement; grew into millions of records
DeviceThe physical device behind a measurement
DeviceMetricMeasurement capabilities of a device
DiagnosticReportStructured clinical results and reports
FlagA state needing attention; the alert when a measurement crosses a threshold
MediaMultimedia attached to workflows
BinaryBinary and document content
SubscriptionEvent-driven notification of downstream services when clinical resources change

A backend layer in front of FHIR, and what never becomes a resource

Neither the clinician portal nor the patient app talks to the FHIR server directly. A backend layer owns authentication and authorization, business logic, orchestration, validation, aggregation, external integrations, device-specific processing and access control. The cost is an extra hop. The gain is a FHIR server that never encodes who may see which patient, never aggregates a dashboard, and never knows about a video provider or a device vendor: a standards-compliant clinical store any external system could integrate with tomorrow. Non-clinical state (session state, configuration, integration bookkeeping) lives in the same layer; forcing it into FHIR inflates resource counts, pollutes searches and ties every application change to the clinical model.

Observation at millions of records: indexing, query patterns, retention

An Observation in FHIR R4 carries the code of what was measured, the subject, the effective time, the value and a device reference. Good for interoperability, expensive at volume: every write is a resource plus its search index entries. Indexing: in a HAPI FHIR JPA server every enabled search parameter costs index writes, so the question is which Observation searches the operational workload needs (by patient, code and date range). Query patterns: the clinician portal reads recent and historical measurements and trends for one patient at a time, so the operational workload centers on patient-scoped, time-bounded searches, and cross-patient questions belong elsewhere. Retention: high-frequency device data need not live in the transactional store forever, so retention belongs in the design, not in a later clean-up.

Analytics separated from the operational FHIR API

Analytical workloads look nothing like transactional clinical reads. A cohort report or a population-wide trend scans wide and aggregates, the access pattern a search-parameter-indexed store handles worst. So the platform included a separate analytics and reporting layer: FHIR data flows into data processing, then analytics services, then reports and dashboards. The HAPI FHIR server serves clinicians and devices; the analytics layer serves questions about the population, so a heavy analytical query never competes with a clinician opening a patient record.

FHIR Subscriptions for event-driven alerting

After a new Observation is stored, backend services evaluate it against configured clinical thresholds; out-of-range values raise a Flag surfaced in the clinician portal. The link is event-driven: FHIR Subscription patterns, where in R4 a Subscription pairs search criteria with a notification channel, let downstream services such as alert evaluation react to newly created or updated clinical resources as events. Four stages stay separate, raw ingestion, clinical persistence, alert evaluation and clinician-facing presentation, which made the system easier to evolve as clinical rules changed: a new threshold is a rule change, not a storage or UI change.

HAPI FHIR on Kubernetes

The HAPI FHIR server ran as a containerized workload on Kubernetes alongside backend services organized by business capability, from clinical data and device integrations to virtual care and analytics. Everything was deployed with Helm and promoted through development, staging and integration, UAT and production by GitOps (Flux) and GitHub Actions, so the FHIR server gets the rollout, restart and replica behaviour an ongoing monitoring workload demands. The honest caveat: a HAPI FHIR server on Kubernetes is a stateless API tier over a database that lives outside the pod lifecycle. The pods scale; the database is the boundary. How the pipeline was built inside ISO 13485 and ISO/IEC 27001 processes is the companion story on healthcare DevOps.

The clinical resource model: Patient at the center, linked to Observation, Device and DeviceMetric, Encounter, Appointment, Practitioner and PractitionerRole, CareTeam, Organization, Flag and DiagnosticReport
The clinical resource model: Patient at the center, with Observation, Device and DeviceMetric, Encounter, Appointment, Practitioner and PractitionerRole, CareTeam, Organization, Flag and DiagnosticReport referencing it.

The Results: One Clinical Model, and Operational APIs That Stay Operational

The outcomes of an architecture engagement are properties, not percentages:

  • One canonical clinical model. Patients, devices, measurements, encounters and alerts exist once, as FHIR R4 resources every service reads the same way.
  • Vendor-specific data never reaches the clinical layer. A new device vendor is an adapter, not a clinical-model change (see the remote patient monitoring story).
  • Analytical queries do not compete with production clinical APIs.
  • The FHIR server is an ordinary Kubernetes workload, Helm-deployed and promoted through four environments by GitOps.
  • A path for clinical workflows. The next direction is structured care pathways on FHIR (PlanDefinition, CarePlan, ServiceRequest, Task, Questionnaire, QuestionnaireResponse).

FHIR is the clinical truth. It is not the application. The moment those two blur, the FHIR server becomes the slowest part of every screen.

Frequently Asked Questions

What is a HAPI FHIR server?

HAPI FHIR is an open-source Java implementation of HL7 FHIR, and a HAPI FHIR server is the ready-to-run FHIR API built on it: it stores resources, exposes the standard RESTful create, read, update, search and history operations, validates them and supports Subscriptions. Here it was the clinical data platform for a remote patient monitoring product, under HL7 FHIR R4 (4.0.1).

Can HAPI FHIR run on Kubernetes in production?

Yes. Here the HAPI FHIR server ran as a containerized workload on Kubernetes, deployed with Helm and promoted by GitOps through development, staging and integration, UAT and production. What makes it work is the surroundings: a database treated as the scaling boundary, a backend layer keeping unbounded queries off the server, and analytics on a separate path.

How do you scale a FHIR server to millions of Observation resources?

Treat the database, not the FHIR server, as the thing you are scaling. Keep operational queries patient-scoped and time-bounded, index only the search parameters the workload needs because each one adds write cost, plan retention for high-frequency device data, and move reporting and population analytics to a separate layer fed from FHIR data, never the production clinical API.

What are the disadvantages of FHIR?

FHIR is verbose, deeply nested and optimised for interoperability, not application convenience. Every clinical fact is a resource with references to resolve, searches are limited to defined search parameters, and high-volume time series such as device Observations grow the database fast. The answer is to scope FHIR, not avoid it: clinical data inside, application state outside, a backend layer in front, analytics elsewhere.

Is HAPI FHIR open source?

Yes. HAPI FHIR is open source under the Apache License and freely usable in commercial products, which is why it is a common foundation for clinical data platforms. It is not free to run: the cost sits in clinical data modeling, the backend layer in front, database growth from Observation volume, Kubernetes operations and regulated-environment process discipline.

Need Senior FHIR and Platform Engineers Inside Your Team?

This platform needed engineers who could decide what belongs in FHIR and how a HAPI FHIR server behaves on Kubernetes at millions of Observations.

Valletta works the forward-deployed way: the engineer who hears your problem joins your product team, builds the clinical data layer and the platform under it with you, and leaves when you can run it without us. Read what a forward deployed engineer is, see our DevOps services, or hire DevOps engineers.

Tell us where your FHIR platform is straining: vallettasoftware.com/contact-us

Related Success Stories

HAPI FHIR Server on Kubernetes: Clinical Data at Scale