Diffing Bundles: Aligning Entries Before Comparing

Editorial illustration in origami-folded style depicting two Bundles with entries aligned by fullUrl before recursive diff

Two Bundles containing the same resources in different order produce an unusable diff. Every entry looks changed because every index shifted. The right pre-diff step is to align entries between the two Bundles so the comparator can diff matching pairs. The site's Resource-vs-resource comparator does this by default when you paste two Bundles. For the wider FHIR framing, our FHIR coverage has more.

Why Alignment Matters

  • Bundle A: [Patient, Observation, Condition]
  • Bundle B: [Observation, Patient, Condition]

Same resources, different order. A positional diff says every entry changed. An aligned diff correctly identifies zero changes.

For the resource-level noise-reduction pattern, diffing two FHIR resources without drowning in reference noise is the entry.

Alignment Keys

Options for aligning entries between Bundles:

  • entry.fullUrl — best for transaction-like Bundles
  • entry.resource.id — good when ids are stable across Bundles
  • entry.resource.resourceType + identifier — for cross-server comparability
  • Content hash — as a last resort

The right key depends on the Bundles. Transactions use fullUrl. Search results use id. Cross-server comparisons use identifier.

When Order Is Load-Bearing

Some Bundles have semantic order:

  • Transaction Bundles — server processes entries in order
  • Message Bundles — event order matters
  • Composition Bundles — narrative section order

For these, do not align by key. Diff by position and treat any order change as a real difference.

For the split, structural diff vs semantic diff for FHIR JSON is the entry.

Handling Unmatched Entries

  • Entry in A but not B — "removed"
  • Entry in B but not A — "added"
  • Entries matched by key — recursive diff

Each category surfaces separately in the output. The comparator groups them for readability.

The Duplicate-Key Case

Two Bundles may have entries with the same key. A single-pass alignment picks one arbitrarily and produces confusing results.

The right pattern:

  • Group entries by key on both sides
  • Pair them up in order within each key group
  • Extra entries in either group become "added" or "removed"

The comparator implements this multi-map pairing by default.

The Very-Large-Bundle Case

Aligning by key requires holding both Bundles in memory. Large Bundles (bulk export shape) may not fit.

Options:

  • Stream, sort both sides externally by key, then merge-diff
  • Chunk by resource type and diff per type
  • Sample and diff representative subsets

For most day-to-day diffing, the in-memory approach is fine. For very large Bundles, the diff tool needs to be a specialized pipeline.

Reference Rewriting During Alignment

Entries in one Bundle may reference each other by urn:uuid: while the other uses server-assigned ids. Aligning without rewriting produces reference-diff noise on every entry.

The right pre-diff: build a URN-to-id map from the alignment step and rewrite references before the recursive diff.

Output Structure

A Bundle diff produces:

  • Per-entry changes with alignment keys
  • Added/removed entries with resource type and key
  • Summary counts

Reviewers can drill in from the summary. Automated tools consume the machine-readable per-entry changes.

For PR review specifically, reviewing FHIR diffs in a pull request is the entry.

Testing The Alignment

Every alignment implementation should be tested on:

  • Same Bundle, same order → empty diff
  • Same content, shuffled order → empty diff (when order is not load-bearing)
  • One entry different → single-entry diff
  • Duplicate keys with different content → per-instance diff

If any of these produce unexpected output, the alignment is wrong.

The Short Version

Align by fullUrl or id before diffing Bundles. Handle unmatched entries as added/removed. Rewrite cross-entry references pre-diff. Preserve order when it is load-bearing. Test the alignment logic explicitly.

Origami-folded diagram of two Bundles with entries in different order being aligned by fullUrl before per-entry recursive diff, drawn as flat paper-fold shapes with soft-blue accents on cream paper

Sources