Two FHIR diffs of the same pair of resources can produce very different output. A structural diff finds every byte-level change. A semantic diff finds every clinically meaningful change. The two are related and different, and knowing which you actually need saves the time of scrolling past irrelevant results. The site's Resource-vs-resource comparator supports both modes. For the wider FHIR framing, the broader FHIR knowledge base has more.
What A Structural Diff Sees
- Every field that differs by any character
- Every ordering difference in arrays
- Every whitespace difference (in some tools)
- Every case difference in strings
A structural diff is agnostic to FHIR semantics. Two identical Observations rendered with different key order produce a diff. That is technically correct and usually unhelpful.
What A Semantic Diff Sees
- Fields that differ in the value they represent
- Array elements that differ regardless of order (when order is not load-bearing)
- Coded values that differ in system or code but not display
- Timestamps that differ but represent the same instant
A semantic diff understands FHIR's shape. It ignores incidentals; it flags actual differences.
For the noise-reduction pattern, diffing two FHIR resources without drowning in reference noise is the entry.
When Structural Wins
- Verifying byte-identical roundtrip through a formatter
- Debugging character-level issues (escape sequences, encoding)
- Signature verification where the exact bytes matter
- Legal or audit contexts where character changes are meaningful
Every one of these needs to see every difference. A semantic diff would hide them.
When Semantic Wins
- Reviewing a change to a fixture — was the clinical meaning changed?
- Comparing outputs from two servers with the same input — do they agree semantically?
- Regression testing — did the payload's meaning change even if bytes did?
- Support triage — is there a real difference in the data?
Every one of these wants only the clinical difference. Structural noise gets in the way.
The Middle Ground
Most day-to-day diffing wants semantic. Most day-to-day tools default to structural. That mismatch is why FHIR-aware diff tools exist — they add the semantic understanding on top of the structural machinery.
The comparator applies a curated set of semantic rules by default and lets you opt into structural mode.
The Ordering Question
In FHIR, some arrays are load-bearing (Bundle.entry in transactions, Observation.component for panels). Some are not (identifier[] where the entries have distinguishing systems).
A semantic diff should know which arrays care about order and which do not. For the deep dive on the ignore side, ignoring meta.lastUpdated without ignoring the wrong things is the entry.
The Coded Value Case
{ "system": "http://loinc.org", "code": "1234-5", "display": "Glucose" } and { "system": "http://loinc.org", "code": "1234-5", "display": "Blood glucose" } differ structurally. Semantically they refer to the same code — display is human text.
A semantic diff can ignore display drift when the system + code matches. A structural diff cannot.
PATCH Generation Needs Structural
If you want to produce a JSON Patch that transforms one resource into another, you need structural precision. Every byte-level change is a candidate patch operation. For the mechanic, PATCH generation from a JSON diff is the entry.
Consistency Across Runs
Both diff modes should be deterministic — same inputs always produce the same output. Non-deterministic diffs are useless for automated review.
Semantic diffs are usually more complex and easier to get non-deterministic. Verify determinism explicitly.
The Short Version
Structural for byte precision. Semantic for clinical meaning. Most day-to-day diffing wants semantic; most default tools do structural. Use the comparator's semantic mode for the human read, structural for the tooling read.

Sources
- HL7 canonical FHIR JSON representation specification - HL7 canonical FHIR JSON representation specification
