FHIR R4 vs FHIR R5: What Healthcare Software Teams Need to Know Before Migrating

Written by Technical Team Last updated 03.09.2026 22 minute read

Home>Insights>FHIR R4 vs FHIR R5: What Healthcare Software Teams Need to Know Before Migrating

FHIR has become one of the most important interoperability standards in modern healthcare software. For engineering teams building electronic patient record integrations, clinical applications, diagnostic platforms, digital health products or healthcare data infrastructure, support for Fast Healthcare Interoperability Resources is increasingly a fundamental architectural requirement rather than an optional integration feature.

However, saying that a system “supports FHIR” is only part of the story.

FHIR is versioned, and different healthcare organisations, vendors, national programmes and implementation guides can depend on different releases of the specification. A product that correctly implements FHIR R4 cannot automatically be assumed to interoperate with an ecosystem using FHIR R5. Likewise, upgrading an existing platform from R4 to R5 is not equivalent to updating an ordinary REST API dependency.

FHIR R5 was published in March 2023 and represents a substantial evolution of the standard. It expands the resource model, improves consistency across several clinical domains, introduces new datatypes and resources, significantly redesigns areas such as subscriptions and continues the gradual maturation of FHIR content towards greater stability.

That does not mean every healthcare software team should immediately migrate.

FHIR R4 remains deeply embedded in production healthcare infrastructure. Many implementation guides, EPR integrations, national interoperability programmes and vendor APIs continue to use R4 or profiles derived from it. For many organisations, therefore, the important engineering question is not simply whether R5 is newer or technically better. It is whether moving to R5 creates enough practical value to justify the compatibility, implementation and operational complexity involved.

A successful migration requires teams to understand the difference between the FHIR specification itself and the interoperability contracts built on top of it. Resource schemas matter, but so do profiles, extensions, terminology bindings, CapabilityStatements, validation rules, search behaviour, subscription mechanisms and assumptions embedded deep within application code.

The most important principle is therefore straightforward: migrating from FHIR R4 to R5 should be treated as an interoperability programme, not as a library upgrade.

Key takeaway: A FHIR R4 to R5 migration is not simply an API or SDK upgrade. Differences in resource models, datatypes, subscriptions, terminology, profiles and implementation guides can affect interoperability across an entire healthcare software platform. For most established systems, the safest FHIR R5 migration strategy is to introduce R5 alongside existing R4 support and move integrations only when trading partners and healthcare ecosystems are ready.

Why FHIR R4 and FHIR R5 Are More Different Than Their Version Numbers Suggest

FHIR versions are not simply successive editions of a static data schema. The specification develops through a maturity process in which individual components can have different levels of stability.

Some parts of FHIR are normative, meaning their future evolution is heavily constrained by compatibility rules. Other components remain at Trial Use or Draft maturity and can undergo more significant structural changes as implementation experience develops.

This distinction is crucial when assessing migration risk.

An engineering team that primarily uses mature infrastructure resources may encounter relatively manageable differences between R4 and R5. A platform heavily dependent on less mature clinical, workflow or specialised resources may experience considerably more substantial changes.

FHIR’s normative compatibility rules are designed to constrain what can happen to mature artefacts. For example, new optional elements can generally be introduced without invalidating older instances, while the identities of established normative resources and elements receive stronger protection.

However, these protections do not mean that R4 and R5 are globally interchangeable.

The FHIR specification contains hundreds of resources, datatypes, terminology bindings, search parameters and operations, and their maturity levels differ. Trial Use content can evolve more significantly between releases. A healthcare product may therefore depend simultaneously on highly stable parts of FHIR and on other structures that have changed considerably.

One of the most visible changes in R5 is the introduction and wider use of the CodeableReference datatype.

Healthcare data frequently encounters a modelling problem: sometimes an application wants to represent a general clinical concept, while at other times it wants to point to a specific resource instance representing that concept.

Consider the reason for a medication.

An application might know only that the medication was prescribed because of hypertension, represented using a terminology code. Alternatively, it may have an actual Condition resource representing the patient’s diagnosed hypertension and want to reference that specific record.

Earlier FHIR designs often represented these possibilities using separate fields such as a coded element and a reference element. R5 increasingly consolidates this pattern using CodeableReference, which can carry either a CodeableConcept, a Reference, or potentially both where appropriate.

This creates a cleaner conceptual model, but it can require meaningful application changes.

A codebase built around separate properties such as reasonCode and reasonReference may have business logic, serializers, database columns, mapping rules and UI components explicitly coupled to those R4 structures. Migrating the FHIR model may therefore require changes well beyond the API boundary.

The difference becomes clearer when the equivalent medication reason is represented in R4 and R5:

// FHIR R4
{
  "reasonCode": [
    {
      "coding": [
        {
          "system": "http://snomed.info/sct",
          "code": "38341003",
          "display": "Hypertensive disorder"
        }
      ]
    }
  ]
}

// FHIR R5
{
  "reason": [
    {
      "concept": {
        "coding": [
          {
            "system": "http://snomed.info/sct",
            "code": "38341003",
            "display": "Hypertensive disorder"
          }
        ]
      }
    }
  ]
}

MedicationRequest illustrates this evolution. In later FHIR modelling, medication itself is represented using a CodeableReference, allowing the request to identify a medication concept or reference a detailed Medication resource through one consistent element. Similar patterns appear elsewhere within R5.

ServiceRequest also demonstrates why teams cannot safely estimate migration effort merely by counting renamed resources. Its code changes from a CodeableConcept to a CodeableReference, while other elements have been restructured, added or changed.

These are semantic changes rather than cosmetic schema changes.

The application must still understand what the data means.

Suppose a service receives an R5 ServiceRequest.code containing a reference rather than a directly coded concept. An R4 application that previously assumed the service code could always be extracted synchronously from a CodeableConcept may now need to resolve another resource, operate on a cached representation or preserve the reference without resolution.

The difference can affect database design, query patterns, validation, caching and even latency.

Resource changes can also consolidate fields. For example, where an R4 resource exposes separate coded and reference-based outcomes, R5 may represent the concept using a common element. Code that previously inspected two independent JSON paths must consequently be redesigned rather than simply renamed.

This is why automated schema conversion alone cannot guarantee a correct migration. Two representations can be mechanically transformable while still carrying different application-level assumptions.

R5 also adds new resources and expands the ability of FHIR to model areas that previously required extensions, implementation-guide-specific approaches or external conventions. That is valuable for new product development, but only if the wider interoperability environment actually supports those resources.

A technically elegant R5 implementation that no trading partner understands is less interoperable than a well-profiled R4 implementation that every required system can exchange reliably.

The target FHIR version must therefore be determined by the ecosystem in which the software operates, not solely by the engineering team’s preference for the latest specification.

The Biggest Engineering Changes: Subscriptions, Resource Models and Terminology

For many integration teams, one of the most strategically important improvements in R5 is the evolution of FHIR subscriptions.

Subscriptions allow applications to receive notifications when relevant events occur rather than continuously polling a FHIR server. This capability is extremely important for event-driven healthcare architectures.

An application might need to react when a new laboratory result becomes available, a patient is admitted, an encounter changes state or another clinically relevant resource changes. Polling can achieve this, but it introduces latency, unnecessary traffic and complicated state management.

The subscription model available in R4 proved useful but exposed limitations as implementations became more sophisticated.

R5 formalises a topic-based architecture built around resources including SubscriptionTopic, Subscription and SubscriptionStatus.

The separation is architecturally significant.

A SubscriptionTopic describes the stream of events to which systems may subscribe. Rather than allowing every subscriber to define arbitrary change criteria independently, a topic can define the meaningful event semantics supported by the server.

A Subscription then represents a client’s request to receive notifications for a particular topic, potentially including supported filtering and delivery configuration.

A simplified R5 Subscription for receiving notifications from an admission-events topic might look like this:

{
  "resourceType": "Subscription",
  "status": "requested",
  "topic": "https://example.org/fhir/SubscriptionTopic/admissions",
  "reason": "Notify the integration platform about patient admissions",
  "channelType": {
    "system": "http://terminology.hl7.org/CodeSystem/subscription-channel-type",
    "code": "rest-hook"
  },
  "endpoint": "https://example.org/fhir-events",
  "contentType": "application/fhir+json",
  "heartbeatPeriod": 60,
  "timeout": 10
}

SubscriptionStatus represents information concerning the subscription and notification process, including event information associated with delivered notifications.

This separation enables a more structured event model.

For platform teams building event-driven clinical systems, this can provide a cleaner boundary between domain events and individual subscribers. Instead of modelling subscriptions as little more than persistent searches, the architecture can explicitly identify healthcare events that the platform intends to expose.

That distinction can matter enormously at scale.

Imagine an EPR integration platform serving dozens of downstream applications. One application wants admission events, another needs discharge events and a third processes changes to diagnostic results.

A purely query-oriented subscription model risks allowing clients to construct subtly different interpretations of the same underlying event. A topic-oriented approach encourages the platform to define canonical event semantics once and expose them consistently.

However, teams migrating existing R4 subscription implementations must recognise that this is not simply a change in JSON structure. Event generation, filtering, delivery guarantees, retry handling, notification payloads, monitoring and subscriber lifecycle management may all need reconsideration.

A production subscription service also raises engineering questions the FHIR representation alone cannot answer.

What happens if a notification endpoint is unavailable?

How are duplicate notifications handled?

How long are failed deliveries retried?

Can consumers safely process events out of order?

How does a consumer reconcile its state after being offline?

How are historical events replayed?

How is authorisation applied to resources referenced by an event?

FHIR provides the interoperability contract, but the distributed-systems architecture remains the responsibility of the implementation.

R5 should therefore encourage teams to evaluate their whole event delivery architecture rather than merely implementing the new resources.

Terminology is another area where migrations frequently become more complicated than anticipated.

FHIR resources rely heavily on coded clinical information. SNOMED CT, LOINC, ICD classifications, UCUM units, national terminologies and local coding systems may all appear within real-world implementations.

FHIR versions can change value sets, terminology bindings or modelling approaches. A validator configured for R5 can consequently behave differently from one configured for R4 even where the JSON appears superficially similar.

This is particularly important where bindings are required or extensible.

Teams should not treat terminology validation as a peripheral concern performed only during certification. Terminology forms part of application semantics. If a workflow assumes that a status, category or clinical concept belongs to a particular set of codes, changes in binding expectations can affect business logic.

Migration testing should therefore include realistic coded data rather than synthetic resources containing only the minimum structural fields needed to pass schema validation.

Engineering teams should particularly investigate:

  • resource elements whose datatype changes between R4 and R5;
  • fields that have been consolidated, removed, renamed or replaced;
  • terminology binding changes relevant to their clinical workflows;
  • changes to reference targets and cardinalities;
  • SearchParameter differences relied upon by production queries;
  • implementation-guide profiles layered on top of the base resources;
  • custom extensions that may now overlap with native R5 functionality.

The last point deserves particular attention.

FHIR extensions are one of the standard’s most useful mechanisms. They allow implementations to represent information that does not exist in the base specification without creating an incompatible proprietary schema.

Over time, however, functionality previously represented through an extension may become part of the core specification.

A migration to R5 can consequently create an architectural choice. Should the product continue using its established extension for backwards compatibility, or should it migrate to the new native R5 element?

Simply retaining every legacy extension forever creates technical debt. Immediately removing them can break compatibility with existing consumers.

Teams need an explicit extension lifecycle strategy.

That strategy should identify the canonical representation used internally, the representation emitted by each API version and the transformation rules between old and new forms.

Why Migrating a FHIR Server Is Not the Same as Migrating a Healthcare Product

FHIR is often described as an API standard, but production healthcare software rarely consists of a FHIR endpoint with nothing behind it.

The FHIR layer usually sits on top of a broader domain model, relational database, event store, integration engine, terminology service or clinical application.

That distinction determines migration difficulty.

If the application’s internal domain model is independent of FHIR, supporting R5 may involve creating a new mapping layer. If the application’s database schema mirrors R4 resources closely, migration can be significantly more invasive.

Neither approach is inherently incorrect.

FHIR-native storage can be extremely useful for platforms whose primary purpose is storing and exchanging FHIR resources. A specialised clinical application, however, may benefit from maintaining its own domain model and treating FHIR as one interoperability representation among several.

Problems arise when teams accidentally allow an external FHIR version to become the implicit internal domain model without making that an intentional architectural decision.

Consider a platform whose application classes are generated directly from R4 StructureDefinitions. Database entities use the same field structure, application services accept those generated types, event messages contain the same resources and business rules navigate them directly.

Moving to R5 now affects nearly every layer.

By contrast, consider a platform that represents a prescription using an internal medication-order model and has separate adapters for R4. Adding R5 may involve implementing another adapter while leaving much of the core application unchanged.

The cost is additional mapping logic, but the benefit is isolation from interoperability-version churn.

For healthcare platforms expected to integrate with multiple organisations over many years, supporting multiple FHIR versions simultaneously can be more realistic than performing a single global migration.

One hospital may expose R4. Another trading partner may adopt an R5-based interface. A national implementation guide may specify a particular version independently of both.

The product may therefore need a version-neutral canonical model.

A useful architecture often looks conceptually like this:

External R4 resource → R4 adapter → canonical domain model → application logic

External R5 resource → R5 adapter → canonical domain model → application logic

Responses then pass through the appropriate adapter in the opposite direction.

This does not eliminate complexity. It relocates the complexity to an explicit interoperability boundary where it can be controlled and tested.

The canonical model also should not be an imaginary “perfect version of FHIR”. It should represent the concepts the application itself requires.

Otherwise the organisation simply creates another healthcare interoperability specification that it must maintain internally.

Version identification is another important concern.

A robust client should not silently assume that every endpoint exposes the same FHIR release. Servers expose capability information through their CapabilityStatement, and integration configuration should record the FHIR version and implementation guide expected from each endpoint.

For example, a FHIR client can inspect the server’s CapabilityStatement before selecting its version-specific adapter:

async function connectToFhirServer(baseUrl) {
  const response = await fetch(`${baseUrl}/metadata`, {
    headers: {
      Accept: "application/fhir+json"
    }
  });

  const capability = await response.json();
  const version = capability.fhirVersion;

  if (version === "4.0.1") {
    return createR4Adapter(baseUrl);
  }

  if (version === "5.0.0") {
    return createR5Adapter(baseUrl);
  }

  throw new Error(`Unsupported FHIR version: ${version}`);
}

In production, the client should also inspect declared profiles, implementation guides and supported interactions rather than relying on the FHIR version alone.

Version-aware behaviour should be deliberate.

A system receiving unknown R5 elements should not necessarily fail merely because they were absent from its R4-era understanding. FHIR’s compatibility philosophy encourages implementations to tolerate certain unknown additions where safe.

Healthcare software, however, has an additional constraint: clinical risk.

Ignoring a field that the application does not understand may be technically permissible in some circumstances, but teams must assess whether losing that information changes clinical meaning.

This is why generic JSON deserialisation policies can become dangerous.

A library configured to discard unknown fields may produce a structurally valid application object while silently removing information the sender considered important. Conversely, configuring the application to fail on every unfamiliar property can undermine forward compatibility.

The right behaviour depends on the resource, profile, workflow and clinical consequences.

Migration therefore needs risk-based parsing rather than a blanket rule.

Persistence creates another complication.

If resources are stored in their original representation, introducing R5 may mean storing multiple schema versions. Teams need to decide whether existing R4 records will be converted, preserved unchanged or transformed dynamically when accessed.

Mass conversion seems attractive because it creates a homogeneous database, but it has consequences.

FHIR conversions are not always perfectly reversible. Information available in one release may not map cleanly to another. A transformation can potentially preserve such data using extensions, but round-trip fidelity must be demonstrated rather than assumed.

In regulated or clinically sensitive environments, retaining the original payload alongside its transformed representation is often valuable for auditability.

That allows engineers to distinguish between what a sending system actually transmitted and what the receiving platform derived from it.

How to Test an R4-to-R5 Migration Without Creating Clinical Risk

FHIR migration testing must go substantially beyond compiling against an R5 SDK and running a collection of happy-path API requests.

Healthcare interoperability failures tend to occur at semantic boundaries.

The JSON parses correctly, but a code is interpreted differently.

A reference resolves correctly, but now points to a resource type the application does not expect.

A transformation succeeds, but drops an extension.

A resource validates against base R5 but violates the implementation guide used by the receiving organisation.

A subscription delivers notifications, but retry behaviour causes duplicate downstream actions.

A search returns valid resources, but different matching behaviour causes records to disappear from an operational workflow.

Testing therefore needs several layers.

Structural validation is the first.

Every produced resource should be validated against the correct R5 base definition and, where applicable, the relevant implementation-guide profiles. Teams should avoid validating only against the FHIR core specification if their actual interoperability contract uses stricter profiles.

Profile validation is effectively contract testing.

If a receiving organisation expects mandatory identifiers, particular SNOMED CT concepts, sliced extensions or restricted reference targets, a resource that is legal according to generic FHIR may still be unusable to that organisation.

Transformation testing is equally important.

For each resource type actually used in production, teams should maintain representative R4 fixtures and verify conversion to R5.

Critically, fixtures should represent real complexity rather than idealised examples.

Tests should contain multiple identifiers, repeated elements, extensions, contained resources, unusual terminology combinations, absent optional data, references, narrative, modifiers where relevant and historically observed edge cases.

Round-trip testing should then answer an important question:

If an R4 resource is converted to R5 and subsequently converted back to R4, is the clinically meaningful information preserved?

Byte-for-byte equality is usually the wrong metric because representations may legitimately differ. Semantic equivalence is what matters.

Teams should explicitly classify transformation differences as lossless, acceptable normalisation or information loss.

Information loss should never be discovered accidentally after deployment.

Search behaviour requires its own test suite.

Clinical applications frequently rely on complex combinations of search parameters, chained searches, includes, reverse includes, dates, token searches, pagination and custom parameters.

Even where core REST semantics are familiar across versions, resource-specific SearchParameters can evolve. Production queries therefore need testing against the new server implementation.

Performance should also be measured.

An R5 migration may change indexing requirements because newly used elements, reference targets or search parameters alter the access patterns of the server.

A query that functioned correctly with a small test dataset can become unacceptable against tens of millions of resources.

For subscription-based architectures, testing should include failure conditions as first-class scenarios.

Disconnect the consumer.

Deliver duplicate events.

Delay notifications.

Process events out of sequence.

Rotate credentials.

Restart the subscription service.

Simulate a burst of thousands of resource changes.

Force downstream timeouts.

Then determine whether the system converges back to a correct state.

Healthcare event processing should ideally be designed around idempotency. Receiving the same notification twice should not result in two clinically meaningful actions where only one was intended.

Observability also needs to be upgraded before migration rather than after it.

A team should be able to trace a request or clinical event from the inbound interface through transformation, validation, persistence and outbound delivery.

At minimum, logs and traces should make it possible to identify the relevant FHIR version, resource type, resource identifier, profile and transformation stage without unnecessarily exposing sensitive patient information.

Migration metrics might include validation failure rates, transformation failures, unknown elements, unsupported terminology codes, failed reference resolution, subscription delivery failures and API latency changes.

Without this visibility, a technically successful deployment can hide interoperability degradation for weeks.

A Practical Migration Strategy for Healthcare Software Teams

The safest approach to FHIR R5 adoption is usually incremental rather than a big-bang replacement of R4.

Start by determining why the organisation wants R5.

“R5 is newer” is not sufficient justification for a migration that touches clinical interoperability.

There should be a concrete capability, partner requirement or architectural objective.

Perhaps a product requires improved subscription functionality. Perhaps an implementation partner is moving to R5. Perhaps a new R5 resource removes the need for a large proprietary extension model. Perhaps an organisation wants to standardise a new platform on the latest mature model while maintaining R4 compatibility at its boundaries.

Once the objective is clear, inventory the current FHIR footprint.

Identify every resource, profile, extension, terminology binding, operation and SearchParameter actually used by the software.

Do not assume that documentation accurately reflects production usage.

Analyse real integration traffic where governance permits. It is common to discover extensions and field combinations introduced years earlier that current engineering teams did not know existed.

Then classify dependencies.

A useful classification is unchanged, compatible addition, transformable change, breaking semantic change and unsupported.

This creates a far more realistic migration plan than simply comparing entire FHIR packages.

Next, analyse the implementation guides on which the product depends.

This is one of the most important stages and one of the easiest to overlook.

Most real healthcare interoperability does not occur against unrestricted base FHIR. It occurs against profiles and implementation guides.

The base FHIR version tells you the language. The implementation guide tells you the actual contract.

If a strategically important ecosystem continues to require R4, removing R4 support merely because the application now supports R5 would be counterproductive.

For many vendors, therefore, the appropriate objective is not “migrate from R4 to R5”.

It is “add a reliable R5 interoperability capability while preserving R4”.

That distinction materially changes the architecture.

A sensible migration programme may proceed through the following stages:

  • isolate R4-specific code behind explicit adapter boundaries;
  • establish a canonical internal representation where appropriate;
  • introduce R5 models and validation without changing production interfaces;
  • create tested R4-to-canonical and R5-to-canonical transformations;
  • validate round-trip behaviour for clinically important data;
  • expose selected R5 endpoints or capabilities alongside R4;
  • migrate consumers individually based on their actual readiness;
  • retire R4 functionality only when ecosystem dependencies genuinely permit it.

Running R4 and R5 simultaneously creates additional operational work, but it also provides a powerful migration safety mechanism.

It allows producers and consumers to move independently.

Versioning should be visible throughout the architecture. API gateways, integration services, message queues and observability tooling should make it clear which representation is being processed.

Avoid architectures where the system silently transforms every incoming resource into whichever FHIR version happens to be used internally. Invisible transformations make incidents much harder to investigate.

Compatibility boundaries should be explicit.

Teams should also resist the temptation to implement every new R5 capability immediately.

FHIR is large because healthcare is large.

Most products use only a fraction of the specification.

The goal is not to maximise the number of R5 resources supported. The goal is to provide dependable interoperability for the clinical and operational workflows the product actually serves.

That means prioritising depth over superficial coverage.

A platform that correctly implements ten resources with robust profiling, terminology validation, search, reference handling, auditability and failure recovery is often more useful than one claiming support for a hundred resources that have only been mapped at schema level.

Finally, migration decisions should consider where FHIR sits within the organisation’s longer-term integration strategy.

R5 adoption can be an opportunity to correct architectural problems accumulated during earlier interoperability programmes.

If every integration currently contains its own bespoke mapping logic, centralising transformation may reduce duplication.

If services consume generated FHIR models directly throughout application logic, introducing adapters may reduce future coupling.

If validation occurs only when data reaches production, moving profile validation into CI/CD can catch contract failures much earlier.

If patient-facing workflows rely on synchronous calls across several remote healthcare systems, the migration may be a useful point at which to reconsider caching, asynchronous processing and failure isolation.

FHIR R5 should therefore not be viewed simply as a destination.

It is an opportunity to improve how the organisation handles healthcare interoperability as an engineering discipline.

The most important lesson is that R4 and R5 are not competing standards where the newest version automatically replaces the previous one. They are releases within an evolving interoperability ecosystem, and healthcare systems will continue to encounter multiple versions for years.

Successful teams design accordingly.

They understand the specification differences, but they also understand their profiles, trading partners, clinical workflows and operational risks. They isolate version-specific concerns where possible. They test semantic transformations rather than assuming successful serialisation means successful interoperability. They maintain observability around the boundaries where information changes representation. And they migrate consumers based on real ecosystem readiness rather than release numbers.

FHIR R5 offers significant improvements, including cleaner modelling in a number of areas, more sophisticated event-driven interoperability and continued maturation of the standard. For greenfield platforms, those improvements may make R5 the natural foundation where the required ecosystem supports it.

For established R4 products, however, the right migration strategy is usually more nuanced.

The objective should not be to replace R4 as quickly as possible.

It should be to introduce R5 without losing interoperability, clinical meaning or operational reliability.

That requires considerably more engineering discipline than changing the version number in a dependency file. But when the migration is approached as an architectural and interoperability programme rather than a schema upgrade, organisations can adopt the advantages of FHIR R5 while continuing to support the healthcare systems that still depend on R4.

Need help with HL7 FHIR implementation?

Is your team looking for help with HL7 FHIR implementation? Click the button below.

Get in touch