FHIR is not an interface. It is an architectural philosophy — one that determines how your data model, API surface, auth layer, and integration topology must all fit together to achieve real interoperability.
FHIR resource types in R4 — most teams use fewer than 30
Faster integration delivery with pre-built FHIR middleware vs. custom mapping
Of EHR vendors now expose FHIR R4 APIs — Epic, Cerner, Athenahealth, eCW
Chapter 1. FHIR Architecture Decision Map
Every FHIR integration begins with three architecture decisions that constrain every subsequent choice. Teams that make these decisions explicitly — before writing integration code — build systems that scale. Teams that defer them build systems that require expensive rewrites.
-
FHIR version contract: R4 is the current mandated baseline under the ONC 21st Century Cures Act and CMS Interoperability Rule. R4B introduced breaking changes to a small set of resources (Citation, Evidence, MedicationKnowledge). R5 is published but not yet required. Declare your target version in a CapabilityStatement before any other technical decision — it governs resource structure, search parameter availability, and terminology binding behavior across the entire integration surface.
-
Integration topology: Point-to-point (your app queries the EHR's FHIR endpoint directly), Hub-and-spoke (a central FHIR server aggregates data from multiple source systems), or Event-driven (Subscriptions or Kafka push data to consumers asynchronously). Each has different latency, consistency, and operational complexity profiles. The right topology depends on your use case — not on convention.
-
Profile conformance tier: Base FHIR (no constraints — maximum flexibility, minimum interoperability), US Core (the ONC-mandated baseline for US data exchange — must-support elements, required terminologies), or Implementation Guide–specific (Da Vinci, Argonaut, mCODE, QI-Core — use-case-specific constraints that build on US Core). Declare your conformance tier in your CapabilityStatement and enforce it with a validation pipeline from day one.
⚠️ Architecture Trap
The "we'll add FHIR profiling later" decision costs 4–6× more than doing it at project start. US Core profiles constrain cardinality (making optional fields required), restrict value sets (narrowing polymorphic types), and enforce must-support semantics. Retrofitting these constraints onto an existing data pipeline means re-mapping, re-validating, and often re-collecting data that was captured in non-conformant formats.
Chapter 2. REST vs Bulk vs Subscriptions
FHIR defines three primary interaction paradigms, each optimized for a different data access pattern. Choosing the wrong paradigm for a use case is one of the most common FHIR architecture mistakes — and one of the easiest to avoid.
FHIR REST API
Synchronous CRUD + Search. Best for: patient-context queries at point-of-care, lookup-driven workflows, app launch (SMART), CDS Hooks data requirements. Not for: bulk data extraction or event-driven notifications.
FHIR Bulk Data ($export)
Async NDJSON export via Group/$export or Patient/$export. Best for: analytics, quality reporting, population health, data warehouse ingestion, payer data pulls. Not for: real-time or patient-context use cases.
FHIR Subscriptions
Topic-based push notifications when resources change. R4: Subscription resource (limited). R5: SubscriptionTopic + SubscriptionStatus (full event streaming). Best for: care alerts, downstream system sync, real-time dashboards.
CDS Hooks
FHIR-adjacent spec for embedding decision support into EHR workflow at clinical hook points (patient-view, order-sign, medication-prescribe, encounter-start). Returns Cards and Actions displayed in EHR UI. Best for: clinical alerts, PA pre-check, care gap surfacing.
💡Architecture Pattern
Most production FHIR architectures use all four paradigms simultaneously — REST for point-of-care app queries, Bulk for nightly analytics sync, Subscriptions for care event alerting, and CDS Hooks for clinical workflow integration. The mistake is trying to force one paradigm to serve all four use cases.
Read more: 10 FHIR Integration Architecture Mistakes That Delay HealthTech Products
Chapter 3. US Core Profiling & StructureDefinitions
Base FHIR resources are deliberately under-constrained — they must serve every healthcare system globally. US Core tightens that contract for the US regulatory context, and Implementation Guide-specific profiles tighten it further for specific use cases. Your architecture must decide which constraint layer is authoritative for each resource type you exchange.
| Resource Type | Base FHIR | US Core 6.1 | Da Vinci (Prior Auth) | mCODE (Oncology) |
|---|---|---|---|---|
| Patient | name 0.. | name 1.. (must-support) | Inherits US Core | Inherits US Core |
| Condition | code 0..1 | code 1..1 ICD-10/SNOMED | Extends for PA context | Primary Cancer Condition profile |
| Observation (Lab) | value[x] 0..1, any type | LOINC code required, valueQuantity preferred | Inherits US Core | Tumor Marker profile |
| MedicationRequest | medication[x] 1..1 | RxNorm code required, dosage must-support | PA medication profile with prior auth extension | Cancer-related medication profile |
| Coverage | No must-support requirements | Limited must-support | HRex Coverage profile — full must-support set | Not covered |
Spec Reference
US Core 6.1.0 (January 2024) is the current ONC-certified baseline for USCDI v3. It adds 10 new profiles including Average Blood Pressure, Care Experience Preference, and Specimen. Your CapabilityStatement should declare.
Peerbits Services - EHR Integration Services | HL7, FHIR & API Healthcare Integration
Chapter 4. SMART on FHIR Auth Architecture
SMART on FHIR is the OAuth 2.0-based authorization framework that governs how applications request and receive scoped access to FHIR resources. SMART v2 (aligned with FHIR R4, required by ONC's HTI-1 rule) introduced asymmetric backend authentication, granular resource-level scopes, and launch context extensions that SMART v1 lacked.
Two Launch Flows SMART defines two primary launch patterns, each suited to a different integration context:
EHR Launch (Patient Context)
EHR initiates app launch with patient context embedded in launch token. App receives patient_id, encounter_id, user identity from EHR. Used for clinician-facing apps embedded in EHR workflow.
Smart Token With Context
Access token includes fhirContext claim with Patient/{id} reference. All FHIR queries are automatically patient-scoped. App never needs to ask "which patient?"
Backend Services (M2M)
Server-to-server integration with no user context. App authenticates using a client_assertion JWT signed with a private key (RS384 or ES384). Used for bulk data pulls, analytics pipelines, system-level operations.
System-Level Access Token
Token granted for system/* scopes. No user context. Must be narrowed to minimum necessary system scopes — never system/. in production. Token lifetime: 5 minutes (never cache beyond expiry).
Peerbits Services - SMART on FHIR App Development
Chapter 5. Hub-and-Spoke vs Event-Driven Topologies
FHIR integration topology — how your systems are wired together — determines your latency profile, consistency guarantees, and operational complexity at scale. Three topologies cover the vast majority of real-world healthcare integration architectures:
Topology 1 — Direct REST (Point-to-Point)
App / Consumer
Issues FHIR GET/POST against source EHR FHIR endpoint directly via SMART access token
EHR FHIR API
Epic Sandbox / Cerner / Athena FHIR R4 endpoint responds synchronously
Use when: Single source system, patient-context queries, low data volume. Avoid when: Multiple source EHRs, offline resilience required, high query volume that may hit EHR rate limits.
Topology 2 — FHIR Aggregation Hub
EHR A (Epic)
FHIR R4
EHR B (Cerner)
FHIR R4
FHIR Hub / MPI
Normalises, de-dupes, patient matches. HAPI FHIR / Azure HDS / HealthLake
All Consumers
Apps, Analytics, Payers, CDS
Use when: Multiple source systems, patient matching across organizations, consumers need a single FHIR endpoint regardless of source. Hub must implement a Master Patient Index (MPI) for cross-system patient identity resolution.
Topology 3 — Event-Driven FHIR Pipeline
EHR / Source
Fires FHIR Subscription notification on resource change event
Event Bus
Kafka / Azure Event Hub / AWS EventBridge. FHIR payload or reference-only notification
Consumers
Care management apps, alerting systems, analytics sinks, downstream FHIR servers
Use when: Real-time alerting (admit/discharge/transfer), downstream system synchronization, care gap notification, population health event streaming. Note: FHIR R5 Subscriptions (SubscriptionTopic model) are significantly more capable than R4's Subscription resource — architect for R5 compatibility if building new.
Chapter 6. HAPI vs Azure HDS vs AWS HealthLake
The FHIR server you choose determines your operational overhead, conformance ceiling, performance floor, and vendor lock-in exposure. There is no universally correct answer — only the right server for your specific deployment context.
| Type | R4 Conformance | R5 Readiness | Best For | Watch Out |
|---|---|---|---|---|
| HAPI FHIR | Full R4 + R4B | R5 support in 7.x | Full control, custom extensions, on-prem/hybrid | Operational burden. Performance tuning required at scale. |
| Azure Health Data Services | Strong R4 conformance | Limited R5 preview | Azure-native stacks, HIPAA BAA, managed ops | Azure vendor dependency. Custom search params limited. |
| AWS HealthLake | R4 with NLP extraction | No R5 roadmap public | AWS-native, built-in NLP, analytics integration | Limited FHIR search expressiveness. Higher per-resource cost. |
| Google Cloud Healthcare API | R4 conformance | R5 in roadmap | GCP-native, DICOM + FHIR in one service, BigQuery integration | Smaller healthcare ecosystem. Less community tooling. |
| Medplum | Strong R4 | Active R5 work | Digital health startups, fast iteration, full-stack FHIR | Younger ecosystem. Enterprise support less mature. |
| Firely Server | Full R4 + R4B | R5 production | Highest conformance fidelity, IG publication, EU market | Commercial licensing cost. Less North America footprint. |
🧭Decision Framework
If you are building a greenfield digital health product on AWS, start with HealthLake for data storage and HAPI FHIR as your API layer. If you are building a health system integration hub on Azure, use Azure Health Data Services. If you need maximum FHIR conformance and custom profile support, HAPI FHIR or Firely Server are the only options that give you full IG customization at every layer.
Chapter 7. HL7 v2 to FHIR R4 Mapping Architecture
The majority of production healthcare data still arrives as HL7 v2 messages — the dominant standard in labs, ADT feeds, radiology, and pharmacy systems built before FHIR existed. A FHIR architecture that ignores v2 is incomplete. HL7 v2-to-FHIR mapping is neither a one-time ETL job nor a library call — it is an ongoing architectural concern because:
-
v2 is implementation-specific. HL7 v2 has dozens of optional fields, custom Z-segments, and per-institution variations. "ADT A01" from Hospital A is structurally different from "ADT A01" from Hospital B. Your mapping layer must be per-source-system configurable, not a single global mapping function.
-
v2 and FHIR have incompatible identity models. v2 uses string identifiers in MSH, PID, PV1 segments. FHIR uses resource references (Patient/123, Encounter/456). Your mapping layer must resolve v2 identifiers to FHIR resource IDs — which requires a running FHIR server to look up or create the referenced resources, not just a field mapping table.
-
v2 terminology ≠ FHIR terminology. v2 uses local codes, NCI codes, LOINC, SNOMED, and proprietary lab codes interchangeably in the same segment. FHIR profiles mandate specific code systems per element. Every v2-to-FHIR mapping must include a terminology translation layer backed by a live terminology service.
// API to AUTH (table) + FHIR Encounter
// next: provides account-identity (patient clinical data
function auxAuth(patIdEncounter,cRef,transMetaSpec) {
const ptd = uIntg.getAsObject('PEM'),
par = uIntg.getAsObject('PAT');
// Slot 1: Slice over encounter resources
const pattern = await fetchClient.resolveResourceDataSet({
localIdentifier: { system: ptd.getProfileId(); analyzeValue.ptd.getField(42) ]
});
// Slot 2: Translate PII (clinician type) is FHIR Encounter.type,
// and partition (patId:orgId:site:authz_ami)
const classCode = await terminologyService.translate({
source: "http://fhir/admin-type",
target: "http://terminology.hl7.org/CodeSystem/v3-ActCode"
});
// Slot 3: Build Encounter resource (us Core Encounter profile)
return {
resourceType: 'Encounter',
status: 'in-progress',
class: { system: classCode, code: par.getField(42) }, // ← slot - in progress
subject: { reference: 'Patient/[patId]', analytics: 'value: ptd.getField(99) ]
period: { start: ptd.getFieldId(45) },
identifier: [{ system: 'urn:oid:your-urg-oid', value: ptd.getField(49) }]
};
}Recommended mapping tooling: HL7's official v2-to-FHIR mapping tables (published as a FHIR Implementation Guide at hl7.org/fhir/uv/v2mappings) are the canonical reference. LinuxForHealth HL7v2-FHIR Converter (open source) provides production-grade Java-based mapping. Microsoft FHIR Converter supports v2, C-CDA, and custom Liquid templates for Azure-native stacks.
Chapter 8. Terminology Service Architecture
Clinical terminology is the connective tissue of FHIR interoperability. FHIR resources encode clinical meaning through coded concepts — LOINC for lab tests and observations, SNOMED CT for clinical findings, RxNorm for medications, ICD-10-CM for diagnoses, CPT for procedures. These code systems are large (SNOMED CT has 350,000+ concepts), versioned (updated quarterly/annually), licensed (CPT requires AMA license), and interdependent (ICD-10 maps to SNOMED maps to LOINC).
The correct architecture treats your FHIR terminology service as shared infrastructure — a dedicated microservice that all FHIR applications call for code validation and cross-system translation, not a library bundled into each service:
FHIR Application
Needs to validate Observation.code is a valid LOINC lab code
Terminology Service
$validate-code / $translate / $expand operations. HAPI FHIR with terminology pack, Ontoserver, or TerminologyServer.net
Code System Store
LOINC, SNOMED CT, RxNorm, ICD-10 — versioned, cached, updated on release schedule
Each service maintains its own static copy of LOINC codes as a lookup table in its database. ICD-10 updated annually in October — services diverge on code versions. RxNorm NDC mappings stale within weeks. Translation logic duplicated across 6 services with 6 different bug sets.
Single shared terminology service exposes FHIR $validate-code, $translate, and $expand endpoints. ValueSet expansions cached with configurable TTL. Version-aware — services can request code validation against a specific code system version. Updates propagated once, used everywhere.
Chapter 9. Clinical Decision Support At the Point of Care
CDS Hooks is the FHIR-aligned specification for embedding clinical decision support into EHR workflow at real-time, point-of-care hook points. It closes the loop between your FHIR data layer and the clinical UI where physicians and nurses make decisions. A FHIR architecture without CDS Hooks delivers data — a FHIR architecture with CDS Hooks delivers intelligence.
| Hook Point | Fires When | FHIR Prefetch Context | High-Value Use Cases |
|---|---|---|---|
| patient-view | Clinician opens patient chart | Patient, Condition, MedicationRequest | Care gaps, chronic care enrollment (CCM/RPM), risk scores, outstanding PAs |
| order-select | Clinician selects an order but before signing | Patient, draft MedicationRequest/ServiceRequest | PA coverage check, formulary guidance, duplicate order alert |
| order-sign | Clinician signs an order (final) | Patient, signed MedicationRequest/ServiceRequest | Final PA eligibility, drug-drug interaction check, dosing alert |
| encounter-start | New encounter created | Patient, Encounter, Condition | CCM eligibility alert, care plan reminder, preventive care due |
| encounter-discharge | Inpatient discharge initiated | Patient, Encounter, Condition | Transition of care checklist, readmission risk score, follow-up scheduling |
Peerbits Services - AI Prior Authorization Automation
Chapter 10. FHIR Validation Pipeline Design
Accepting malformed FHIR resources silently is the most insidious form of data quality degradation in healthcare integration. A Condition resource with a code from the wrong code system is structurally valid — it will pass JSON parsing — but it will fail profile validation and produce incorrect clinical data downstream. Your FHIR architecture must include a multi-layer validation pipeline that runs on every inbound resource before it reaches your data store.
Layer 1 — Structural
JSON/XML well-formedness. FHIR base resource validation. Required fields. Correct data types. Cardinality constraints. Run: HAPI FHIR Validator or HL7 Validator CLI
Layer 2 — Profile
StructureDefinition conformance. Must-support element presence. FHIRPath invariant rules. Slice validation. US Core / IG conformance. Run: same validator + loaded IGs
Layer 3 — Terminology
Code system membership ($validate-code). ValueSet binding enforcement. Required vs preferred vs extensible binding. Run: Terminology Service $validate-code operation
Layer 4 — Business Rules
Clinical plausibility checks. Referential integrity within Bundles. Organization-specific rules not encodable in profiles. Run: Custom FHIRPath rules or rule engine
Dead Letter Queue
Validation failures routed here. Never silently dropped. Never auto-corrected. Human review required. Failure taxonomy logged for source system improvement feedback.
💡Production Pattern
Run Layer 1–2 validation synchronously in the request path for FHIR REST interactions — return an OperationOutcome with validation errors in the HTTP response body. Run Layer 3–4 asynchronously post-accept for bulk ingestion pipelines where synchronous terminology lookup would introduce unacceptable latency.
Chapter 11. Production FHIR Monitoring
Standard HTTP monitoring misses most FHIR-specific failure modes. A FHIR server that returns HTTP 200 with an OperationOutcome resource containing errors is succeeding at HTTP and failing at FHIR simultaneously. A Bulk export job that returns 202 Accepted and then silently fails midway through generating output files leaves no visible HTTP error. Your observability stack must understand FHIR semantics — not just HTTP semantics.
FHIR-Specific Metrics to Instrument
-
OperationOutcome error rate by resource type and issue code. Track the percentage of FHIR responses containing OperationOutcome resources with severity "error" or "fatal" — broken out by resource type (Patient, Observation, MedicationRequest) and issue code (required, value, invalid). This is your data quality leading indicator.
-
FHIR search result-set distribution. Track p50/p95/p99 result counts per search operation type. A sudden shift toward zero-result searches for a parameter that normally returns results indicates a bug in search parameter handling or a source data quality regression — not a legitimate empty result set.
-
Bulk export job completion rate and NDJSON file integrity. Track the percentage of $export jobs that complete vs. fail vs. expire. For completed jobs, validate NDJSON file line counts against expected population size. A completed export with 10% fewer lines than expected is a silent data loss event.
-
SMART token grant failure rate by error type. Distinguish between invalid_client (key registration issue), invalid_scope (scope not permitted), and server errors. Token grant failures are clinical access failures — they must alert, not just log.
-
Terminology validation cache hit rate and error rate. A terminology cache miss on a required code system (LOINC unavailable) that causes validation to fail silently is a production incident. Track terminology service availability separately from FHIR server availability.
Chapter 12. FHIR R5 Migration Readiness
FHIR R5 was published in March 2023. While no major regulatory mandate requires R5 adoption today, Epic's Sandbox, Firely Server, and HAPI FHIR 7.x already expose R5 endpoints. CMS Interoperability rulemaking for 2026+ is expected to reference R5 or R5-aligned IGs. Building R5 readiness into your architecture now costs significantly less than migrating under regulatory pressure later.
Breaking Changes from R4 to R5 That Affect Most Integrations
| Area | R4 Behavior | R5 Change | Migration Complexity |
|---|---|---|---|
| Subscriptions | Subscription resource (limited topic support) | SubscriptionTopic + SubscriptionStatus — full event streaming model | High — complete architectural redesign of event pipeline |
| VersionIndependent References | Reference.reference is a URL string | Reference.identifier added as canonical alternative | Medium — update reference resolution logic |
| MedicationRequest | medication[x] polymorphic | medication CodeableReference — more expressive | Medium — update medication reference handling |
| AuditEvent | AuditEvent resource (limited structure) | Significantly restructured for ATNA alignment | High — rebuild audit logging pipeline |
| CapabilityStatement | CapabilityStatement.rest | Minor additions — backward compatible | Low — additive changes only |
🔭R5 Readiness Recommendation
Build your FHIR version negotiation layer now — every client request should declare Accept: application/fhir+json; fhirVersion=4.0 explicitly. Your FHIR server should respond with the version it served from the Content-Type header. This makes a future version migration a routing configuration change, not a client application rebuild. If you are building a new Subscriptions pipeline, implement the R5 SubscriptionTopic model from the start — HAPI FHIR 7.x supports it in R4 compatibility mode.
Start With Architecture, Not Configuration
Every FHIR integration that collapses at scale made its fatal decisions in the first two weeks — wrong version contract, wrong topology, wrong profile tier, wrong server. Peerbits has architected FHIR integration stacks across Epic, Cerner, Oracle Health, Athenahealth, and eClinicalWorks environments, from single-source point-of-care apps to multi-EHR population health hubs serving millions of patients.
Our FHIR Architecture Review is a 5-day engagement delivering a full integration stack assessment, CapabilityStatement gap analysis, US Core conformance scorecard, and a documented architecture decision record (ADR) set for your engineering team. Delivered as a written report with a prioritized implementation roadmap.
Book Free FHIR Architecture Review







