FHIR is a data model before it is an API
Teams usually meet FHIR as a set of REST endpoints and conclude that adopting it is an interface exercise. The endpoints are the easy part. What the standard actually requires is that clinical information already exists in your system as discrete, identified, coded elements that can be assembled into resources, and most hospital systems satisfy that only partly.
A resource is a defined structure with required elements, cardinality rules, and expected value sets. An Observation without a code and a value is not an Observation; it is a string that happens to occupy a database column. Validation will reject it, and no amount of transformation logic invents clinical detail that was never captured.
So the honest first question is not which library to use. It is which of your clinical documents are structured today, which are free text, and which are images of paper. That inventory determines the size of the work far more than any technology choice.

Which resources carry which clinical content
The mapping is more predictable than teams expect. Patient, Practitioner, and Organization carry identity; Encounter frames the visit or admission; Condition carries diagnoses and problems; Observation carries vitals and individual laboratory results; DiagnosticReport groups results with an interpretation; MedicationRequest carries a prescribed item. AllergyIntolerance, Procedure, and Immunization cover most of the remaining common ground.
A whole clinical document such as an outpatient consultation note or a discharge summary is not a single resource. It is a Composition providing narrative structure and section ordering, packaged with the resources it references into a Bundle. A system that can emit individual results but has no concept of document assembly is only halfway there.
Work through your actual forms rather than a generic list. Take a real discharge summary, mark every field, and identify the resource and element each one belongs to. Fields with no home will need either a structured capture change or an extension, and finding them now is far cheaper than finding them during validation.

Common resource mappings
- Diagnoses and problems to Condition
- Vitals and individual results to Observation
- Grouped results with interpretation to DiagnosticReport
- Prescribed medicines to MedicationRequest
- Notes and summaries to Composition within a Bundle
References and identifiers are what hold a bundle together
Resources are joined by references, and a bundle is meaningful only if those references resolve. An Observation points to the Patient it concerns and the Encounter it arose in, while a DiagnosticReport points to the Observations it contains and the professional who authorised it. When identifiers are inconsistent across modules, these references break in ways that pass a syntax check and fail a semantic one.
Hospitals running separate laboratory, pharmacy, and billing databases meet their integration debt at precisely this point. If the laboratory system holds its own patient numbering and the link to the main record is a nightly reconciliation, assembling a valid bundle at request time is not straightforward. A master patient index becomes a prerequisite rather than an improvement project.
Provenance matters as much as structure. A receiving clinician needs to know which facility and which professional produced a record and when, which is why registry identities and record format are parts of the same problem. Records that cannot be attributed are of limited clinical use however well formed they are.

Why retrofitting costs more than teams expect
The expense of retrofitting FHIR rarely lies in writing serialisation code. It falls in four other places: capturing data that was never captured discretely, coding data recorded as text, resolving identity across modules, and changing documentation habits so the new fields are actually filled. Each of those involves people rather than software.
There is a performance dimension that surfaces late as well. Assembling a document bundle on demand means reading across several modules inside a request timeout, and systems designed around overnight batch reporting often cannot manage it at interactive speed. Discovering this during sandbox testing is a common and avoidable setback.
A system built with structured capture and a single patient identity from the outset absorbs FHIR at a fraction of the cost. That is a reason to ask about record structure when selecting a platform rather than treating standards support as a checkbox. HealUDoc's EHR (/ehr) captures clinical data as discrete coded elements, which is the property that makes standards work tractable.

Where retrofit cost actually lands
- Discrete capture for data previously free text
- Coding and terminology binding
- Patient identity resolution across modules
- Clinical documentation behaviour change
- On-demand assembly within request timeouts
Terminology is the part that stays unfinished
A structurally valid resource can still be clinically useless if its codes are local. A laboratory result carrying an in-house analyser code means nothing to a receiving system, and a medicine recorded as a brand string cannot be checked for interactions elsewhere. Structure and terminology are separate problems and are usually solved on separate timelines.
Plan a mapping layer with owners, effective dates, and a review trigger whenever a source catalogue changes. Route unmapped items to a visible exception queue rather than a default code, because a default code is how unmapped items become invisible. Expect the queue never to reach zero and staff it accordingly.
Be realistic about coverage in the first release. Mapping the highest-volume tests, medicines, and diagnoses delivers most of the clinical value, and chasing complete coverage before go-live delays everything for diminishing returns. Publish what is mapped and what is not, so receiving clinicians understand the limits of what they are reading.

Validate continuously, not at the end
Build validation into the pipeline from the first resource you generate rather than treating it as a pre-submission gate. Structural validation against the specification catches missing elements and cardinality errors, and a second layer should check clinical plausibility such as impossible dates, absent units, and results without reference context. Both should run against real anonymised records, not synthetic examples built to pass.
Test the awkward cases deliberately, because that is where production breaks: amended results, cancelled encounters, merged patient identities, transfers between branches, and records authored by a clinician who has since left. These are ordinary hospital events and each has a defined representation in the standard. A pipeline handling only the clean case will fail in its first month.
Keep a versioned record of your profiles, mappings, and validation rules, and put changes to them under the same control as clinical configuration. A record generated last year should remain explainable this year. Standards work is maintenance, not a milestone that closes.
“Our FHIR project was ninety percent documentation change and ten percent code. We had budgeted it the other way round.”