The DiagnosticReport resource is the cornerstone of lab data representation in FHIR R4. It serves as the container that ties together a patient, a set of test results, the performing laboratory, and the clinical context into a single, structured entity. If you are integrating lab data into an EHR system, building a lab results viewer, or consuming output from an extraction API, understanding DiagnosticReport in depth is essential.
This article provides a thorough walkthrough of the DiagnosticReport resource: its fields, its lifecycle, its relationship to other resources, and the common pitfalls that trip up implementers.
What DiagnosticReport represents
In the FHIR data model, a DiagnosticReport represents the findings and interpretation produced by a diagnostic service. While it can represent radiology reports, pathology reports, or genetic test results, its most common use in clinical informatics is to represent a laboratory report.
A single DiagnosticReport corresponds to one lab report — the document a clinician would review to see a patient's test results. The report contains references to individual Observation resources (one per test result), metadata about when the tests were performed and when the report was finalized, and optionally a reference to the original document (as a PDF or image).
DiagnosticReport vs. Observation
The distinction between DiagnosticReport and Observation is fundamental:
- Observation represents a single test result: one analyte, one value, one LOINC code.
- DiagnosticReport represents the report that groups those results. It carries its own LOINC code (typically a panel code like
58410-2for CBC), a status, and references to all constituent Observations.
You cannot have Observations floating without a parent DiagnosticReport in a well-structured FHIR implementation. The DiagnosticReport provides the clinical context — who ordered the tests, when they were collected, and what the overall interpretation is.
DiagnosticReport structure walkthrough
Let us examine every field of a DiagnosticReport relevant to lab data, with practical guidance on how to populate each one.
Resource type and ID
{
"resourceType": "DiagnosticReport",
"id": "report-cbc-2026-03-01"
}
The id is assigned by the FHIR server upon creation. When submitting via a Transaction Bundle, use a urn:uuid: identifier in the fullUrl field instead.
Status
The status field tracks the lifecycle of the report. FHIR defines the following values:
| Status | Meaning | When to use |
|--------|---------|-------------|
| registered | The report has been registered but results are not yet available | Order received, no results |
| partial | Some but not all results are available | Preliminary results from fast turnaround tests |
| preliminary | Results are available but not yet verified | Auto-released results pending pathologist review |
| final | The report is complete and verified | Most common for lab extraction output |
| amended | The report was modified after being finalized | Correction of a previously reported value |
| corrected | The report was corrected (equivalent to amended in most implementations) | Correction scenario |
| appended | Additional results were added to a final report | Late-arriving results |
| cancelled | The report was cancelled and should be disregarded | Order cancelled |
| entered-in-error | The report was entered in error | Data entry mistake |
For extraction pipelines that process completed lab reports, final is almost always the correct status. Use amended if you are updating a previously submitted report.
Category
The category classifies the type of diagnostic report. For lab data, use the HL7 V2 diagnostic service section code:
{
"category": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v2-0074",
"code": "LAB",
"display": "Laboratory"
}]
}]
}
Some implementations further subdivide the category. A chemistry panel might carry both LAB and a more specific code like CH (Chemistry). However, the LAB category alone is sufficient for most integration scenarios.
Code
The code field identifies what the report covers. For lab reports, this is typically a LOINC panel code:
{
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "58410-2",
"display": "CBC panel - Blood by Automated count"
}],
"text": "Hemograma completo"
}
}
The text field should carry the original panel name from the source document. When the report covers multiple panels (e.g., CBC + metabolic panel), you have two options:
- Create a single DiagnosticReport with a general code (
11502-2, "Laboratory report") and reference all Observations. - Create multiple DiagnosticReports, one per panel, each with its specific panel code.
Option 1 is simpler and is the approach most extraction pipelines use. Option 2 provides finer-grained organization but adds complexity.
Subject
The subject field references the patient:
{
"subject": {
"reference": "Patient/patient-1",
"display": "Garcia, Maria"
}
}
In extraction scenarios where the patient is not registered in the target FHIR server, use a logical reference with an identifier:
{
"subject": {
"identifier": {
"system": "http://hospital.example.org/mrn",
"value": "MRN-12345"
},
"display": "Garcia, Maria"
}
}
Effective date and issued date
Two temporal fields are critical:
- effectiveDateTime: When the specimen was collected or the test was performed. This is the clinically relevant date.
- issued: When the report was issued (made available). This is typically later than the effective date.
{
"effectiveDateTime": "2026-03-01T08:30:00Z",
"issued": "2026-03-01T14:00:00+01:00"
}
For extraction from paper reports, the effective date corresponds to the specimen collection date printed on the report, and the issued date corresponds to the report date. If only one date is available, use it for both fields.
Performer
The performer field identifies who is responsible for the report. For lab data, this is typically the performing laboratory:
{
"performer": [{
"reference": "Organization/lab-central",
"display": "Laboratorio Central Hospital Universitario"
}]
}
Result references
The result array references all Observation resources that are part of this report:
{
"result": [
{ "reference": "Observation/obs-hgb-1", "display": "Hemoglobin" },
{ "reference": "Observation/obs-wbc-1", "display": "White Blood Cells" },
{ "reference": "Observation/obs-plt-1", "display": "Platelets" },
{ "reference": "Observation/obs-hct-1", "display": "Hematocrit" },
{ "reference": "Observation/obs-rbc-1", "display": "Red Blood Cells" }
]
}
In a Transaction Bundle, these references use urn:uuid: identifiers that the server resolves to actual resource IDs.
Presented form
The presentedForm field can carry the original document as an attachment:
{
"presentedForm": [{
"contentType": "application/pdf",
"url": "https://storage.example.org/reports/report-2026-03-01.pdf",
"title": "Informe de laboratorio"
}]
}
This is valuable for auditing — clinicians can compare the structured data against the original document. The attachment can be a URL reference to the stored document or a base64-encoded inline representation (though inline encoding is discouraged for large files).
Complete DiagnosticReport example
Here is a fully populated DiagnosticReport for a CBC panel:
{
"resourceType": "DiagnosticReport",
"id": "report-cbc-001",
"meta": {
"profile": [
"http://hl7.org/fhir/StructureDefinition/DiagnosticReport"
]
},
"status": "final",
"category": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/v2-0074",
"code": "LAB",
"display": "Laboratory"
}]
}],
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "58410-2",
"display": "CBC panel - Blood by Automated count"
}],
"text": "Hemograma completo"
},
"subject": {
"reference": "Patient/patient-1",
"display": "Garcia, Maria"
},
"effectiveDateTime": "2026-03-01T08:30:00Z",
"issued": "2026-03-01T14:00:00Z",
"performer": [{
"reference": "Organization/lab-central",
"display": "Laboratorio Central"
}],
"result": [
{ "reference": "Observation/obs-hgb-1" },
{ "reference": "Observation/obs-wbc-1" },
{ "reference": "Observation/obs-plt-1" },
{ "reference": "Observation/obs-hct-1" },
{ "reference": "Observation/obs-rbc-1" },
{ "reference": "Observation/obs-mcv-1" },
{ "reference": "Observation/obs-mch-1" },
{ "reference": "Observation/obs-mchc-1" }
],
"conclusion": "All values within normal limits.",
"presentedForm": [{
"contentType": "application/pdf",
"url": "https://storage.example.org/reports/cbc-001.pdf",
"title": "Original lab report"
}]
}
Relationship to Observation resources
The DiagnosticReport and its referenced Observations form a parent-child relationship. Several design principles apply.
One Observation per test result
Each discrete test result (hemoglobin, glucose, platelet count) should be a separate Observation. Do not combine multiple results into a single Observation — this breaks the FHIR data model and prevents individual results from being queried, trended, or referenced independently.
Observation.category
Every lab Observation should carry the laboratory category:
{
"category": [{
"coding": [{
"system": "http://terminology.hl7.org/CodeSystem/observation-category",
"code": "laboratory"
}]
}]
}
Back-reference from Observation
While not required by the specification, many implementations include a reference from the Observation back to its parent DiagnosticReport using the derivedFrom or a custom extension. This simplifies queries that start from an Observation and need to find its containing report.
Panel observations
LOINC defines panel codes (like 58410-2 for CBC) that group individual member codes. FHIR supports this with the hasMember field on Observation, where a panel observation references its member observations:
{
"resourceType": "Observation",
"code": {
"coding": [{
"system": "http://loinc.org",
"code": "58410-2",
"display": "CBC panel"
}]
},
"hasMember": [
{ "reference": "Observation/obs-hgb-1" },
{ "reference": "Observation/obs-wbc-1" }
]
}
However, this additional layer is optional. Many implementations skip the panel Observation and let the DiagnosticReport directly reference the individual Observations.
Common implementation pitfalls
Pitfall 1: Missing status field
The status field is required (cardinality 1..1). Omitting it causes validation errors on every FHIR server. Always set status, even if the report lifecycle is simple and all reports are final.
Pitfall 2: Incorrect code system URIs
FHIR is strict about code system URIs. The LOINC system URI must be exactly http://loinc.org (not https://, not http://loinc.org/, not urn:oid:2.16.840.1.113883.6.1). Similarly, UCUM must be http://unitsofmeasure.org. Incorrect URIs will fail validation and may cause downstream systems to misinterpret codes.
Pitfall 3: Orphaned Observations
Submitting Observations without a parent DiagnosticReport creates data that is difficult to interpret and manage. Always create the DiagnosticReport in the same Transaction Bundle as its Observations.
Pitfall 4: Ignoring duplicate detection
If the same lab report is submitted twice (due to network retries, reprocessing, or system errors), the target server will create duplicate resources. Implement idempotency using conditional creates:
{
"request": {
"method": "POST",
"url": "DiagnosticReport",
"ifNoneExist": "identifier=http://lab.example.org/reports|RPT-2026-001"
}
}
This tells the server to skip creation if a DiagnosticReport with that identifier already exists.
Pitfall 5: Incorrect date formats
FHIR uses ISO 8601 date formats. The effectiveDateTime field accepts dates (2026-03-01), date-times (2026-03-01T08:30:00Z), and date-times with timezone offsets (2026-03-01T08:30:00+01:00). Using non-ISO formats or omitting timezone information leads to ambiguous timestamps.
Pitfall 6: Missing reference integrity
In a Transaction Bundle, every reference must resolve to a resource within the bundle or to an existing resource on the server. If an Observation references Patient/patient-1 but that Patient does not exist on the server and is not in the bundle, the transaction will fail. Use conditional references or include all referenced resources in the bundle.
Profiles and constraints
Base FHIR DiagnosticReport is intentionally flexible. Profiles constrain it for specific use cases.
IPS (International Patient Summary)
The IPS profile requires that DiagnosticReport include at minimum: status, code, subject, and at least one result reference. The code must come from a defined value set that includes LOINC lab panel codes.
EU Laboratory Report
The HL7 Europe laboratory report profile adds requirements specific to European cross-border exchange:
- The performer must include the laboratory's organizational identifier.
- The code must use LOINC.
- Results must reference EU Lab Observation profiles.
- The specimen resource is mandatory (not optional as in the base spec).
US Core DiagnosticReport for Laboratory Results
The US Core profile requires:
- A
categoryofLAB. - A
codefrom a required value set. - A
subjectreference to a US Core Patient. - An
effectiveDateTimeoreffectivePeriod.
Implementing the correct profile depends on your target market and regulatory requirements. For EU deployments, the EU Laboratory Report profile aligns with EHDS requirements. For US deployments, US Core is the baseline.
Querying DiagnosticReports
FHIR servers support searching for DiagnosticReports using standard search parameters.
Common search queries
Search for all lab reports for a patient:
GET /DiagnosticReport?patient=Patient/patient-1&category=LAB
Search for reports within a date range:
GET /DiagnosticReport?patient=Patient/patient-1&date=ge2026-01-01&date=le2026-03-31
Search for reports containing a specific test (by LOINC code):
GET /DiagnosticReport?result.code=http://loinc.org|718-7
Search for reports by status:
GET /DiagnosticReport?patient=Patient/patient-1&status=final
Include referenced Observations
To retrieve a DiagnosticReport along with all its referenced Observations in a single request, use the _include parameter:
GET /DiagnosticReport?patient=Patient/patient-1&_include=DiagnosticReport:result
The server returns a search-set Bundle containing the DiagnosticReport and all referenced Observation resources.
DiagnosticReport in the extraction pipeline
When building a lab data extraction pipeline, the DiagnosticReport is typically the last resource assembled. The workflow is:
- Extract test results from the document (OCR, parsing).
- Map each test to a LOINC code.
- Create an Observation for each test result.
- Create a DiagnosticReport referencing all Observations.
- Wrap in a Transaction Bundle for atomic submission.
MedExtract's API handles this entire workflow. You send a lab report document and receive a FHIR R4 Transaction Bundle with a properly populated DiagnosticReport and all associated Observations. The output is validated against the base R4 specification and optionally against EU Lab profiles.
To see how DiagnosticReport fits into the broader FHIR integration picture, read our FHIR R4 implementation guide. For details on how LOINC codes are assigned to Observations, see our complete guide to LOINC extraction.
For hands-on evaluation:
- Review the API documentation for FHIR output format details
- Request a demo to see DiagnosticReport output from your own lab reports
Related Articles
FHIR R4 Implementation for Healthcare
Practical guide to implementing FHIR R4 in healthcare systems: resources, bundles, endpoints, and integration best practices.
FHIR R4 Integration Guide for EHR Systems
A practical overview of integrating FHIR R4 resources into EHR systems, focusing on DiagnosticReport and Observation bundles from lab data.
Complete Guide to LOINC Code Extraction
Everything about automated LOINC code extraction from lab reports: process, challenges, dictionaries, and best practices.