Diffing an R4 payload against an R5 payload is not the same as diffing two R4 payloads. Structural changes between the versions produce diffs on every resource that touched them — Subscription changed shape, MedicationRequest reorganized, Bundle tightened. Treating those version-level shifts as "changes" produces noise that swamps any real semantic difference. The site's Resource-vs-resource comparator supports version-aware mode. For the wider FHIR framing, related FHIR explainers has more.
What Changed Between R4 And R5
- Subscription — split into SubscriptionTopic + Subscription
- MedicationRequest — dosage instruction reshaped
- Bundle — tighter partial-failure rules
- CapabilityStatement — added bulk-data and terminology fields
- Handful of new resources for actors, subscription topics
Most resources carry over with modest edits. The five above changed enough that a naive cross-version diff produces noise on every payload.
The Naïve Cross-Version Diff
Diff an R4 Subscription against an R5 Subscription and you get:
- Fields present in R4, absent in R5 — many marked "removed"
- Fields present in R5, absent in R4 — many marked "added"
- Restructured elements — "path changed"
None of that is meaningful. It is just the versions being different.
The Version-Aware Diff
A version-aware diff:
- Recognizes which fields shifted between versions
- Treats those shifts as expected, not as changes
- Surfaces only the semantic differences between the two payloads
That is a much smaller diff. It is what a human reviewer actually needs.
For the base pattern of ignoring noise, structural diff vs semantic diff for FHIR JSON is the entry.
Version Migration Tables
The FHIR spec publishes migration tables — how R4 fields map to R5 fields. A version-aware diff consumes those tables to map the R4 shape into the R5 shape (or vice versa) before comparing.
The comparator ships with the R4-to-R5 map baked in. For custom versions or migration paths, the map has to be provided.
The Reference Case Across Versions
References that pointed at R4 resources should be updated when the payload moves to R5. A diff should distinguish:
- Reference updated intentionally (the target moved)
- Reference structural change (URL format or version marker)
The former is a semantic change. The latter is expected and should be filtered.
The Terminology Drift Case
R4 and R5 use overlapping but not identical terminology bindings. A code that was valid in R4 may not be valid in R5.
A diff that flags every terminology binding difference produces noise. A version-aware diff filters out expected binding drift.
PATCH Across Versions
Producing a JSON Patch that transforms an R4 payload into an R5 payload is possible but rare. Usually the pattern is:
- Migrate R4 to R5 with a documented mapping
- Store both versions during the transition
- Diff each version against its version-native predecessors
For the patch mechanic, PATCH generation from a JSON diff is the entry.
Merge Across Versions
Merging changes across FHIR versions is not a simple diff-merge — it is a version migration plus a diff-merge. For the base merge framing, when a diff should be a merge conflict is the entry.
The Common Workflow
- Producer emits payloads in R4
- Consumer accepts R5
- Middleware converts R4 to R5
- Both versions get stored for audit
- Diffs run within-version, not across-version
Storing both versions means every downstream tool can pick its native version and never has to do cross-version diffing.
What The Tool Does
The comparator detects the FHIR version from meta.profile URLs or explicit configuration. It applies the version-aware ignore list. Users can override.
The Short Version
Cross-version diffs need version-aware handling. Subscription, MedicationRequest, and Bundle are the resources that changed enough to matter. Version migration tables drive the shape map. Store both versions during transition. Diff within-version when possible.

Sources
- HL7 canonical R5 versions chapter documenting major changes - HL7 canonical R5 versions chapter documenting major changes from R4
