The only open source Java EMR that stores patient data natively as FHIR R4 — not translated, not wrapped, not exported. 16 clinical modules, SMART on FHIR v2.0, DHIS2 national reporting, and a complete insurance revenue cycle. One command to deploy.
The JamEMR difference
Every other open source EMR stores data in a proprietary schema and bolts FHIR on top. JamEMR uses HAPI FHIR JPA as its only database — zero translation overhead, full interoperability from day one.
Patient and Encounter to Coverage, Claim, ClaimResponse, and AuditEvent. Any FHIR-capable system integrates directly. No custom adapter work, ever.allowedDependencies verified by ModularStructureTest on every Maven build. Feature-flagged with @ConditionalOnProperty — zero startup cost for unused modules.VitalsSavedEvent triggers NEWS2. MedicationSavedEvent triggers drug-allergy. StdDiagnosisConfirmedEvent triggers contact tracing. Each is a typed Java record.CompletableFuture, cached for 60 seconds with a 200-entry maximum. Always fast — even on large datasets.DocumentReference resources with LOINC codes 57833-6 (prescription) and 34133-9 (summary of episode note).Questionnaire + QuestionnaireResponse with group nesting, conditional logic, LOINC codes per item, and all FHIR item types.Clinical modules
Feature flags via @ConditionalOnProperty mean unused modules never start. Configure once in Docker Compose; override any flag per environment with a single environment variable.
Complete clinical timeline: encounters, allergies, ICD-10 conditions, LOINC-coded vitals, MedicationRequest prescriptions, CVX-coded immunisations, diagnostic reports, procedures, family history, documents. MRN and blood group as FHIR extensions.
7-day calendar view, per-practitioner queues with sequential token assignment, receptionist check-in / call / no-show / undo flow, and a public TV display at /queue/display/ — no auth required, designed for lobby screens.
FHIR-native revenue cycle, three phases complete. Phase 1: Coverage + InsurancePlan. Phase 2: Claim generation from Invoice — pre-tax lines, duplicate-claim guard. Phase 3: ClaimResponse adjudication, automatic Invoice reconciliation with gap invoicing.
Drug-allergy checker with three-level matching (exact SNOMED → display overlap → drug class cross-reactivity). NEWS2 (0–20) fires on every vitals save, stored as FHIR RiskAssessment. Persistent DetectedIssue alerts on the patient chart.
Complete ART programme: enrolment (EpisodeOfCare), viral load and CD4 trend observations, WHO clinical staging, regimen prescribing and switching. All routes require ROLE_HIV_PROVIDER via @PreAuthorize — enforced at the service layer.
WHO growth monitoring with z-scores: WAZ, HAZ, WHZ, MUAC. Interactive Chart.js growth charts. WHO EPI vaccination schedule with due/overdue/given status per antigen. Weight-based dosing calculator with dose capping and age-band validation.
FHIR-to-analytics ETL (nightly 2 AM or manual trigger), 7 operational reports. Aggregates OPD, malaria (ICD-10 B50–B54), TB, NCDs, EPI vaccine doses by CVX code. Exports as DHIS2 dataValueSet JSON, PEPFAR DATIM, or HMIS CSV.
Complete SMART App Launch v2.0: PKCE S256 with 128-character code_verifier at RFC 7636 maximum length, RS256 id_token validation via Nimbus JOSE+JWT against RemoteJWKSet, proactive token refresh 120s before expiry, session fixation protection. Launches from Epic, Cerner.
Live ward dashboard with FHIR Location-based bed grid, admissions via EpisodeOfCare, SOAP ward-round notes with inline vitals, patient transfer, and discharge with disposition coding. Bed lifecycle: Available → Occupied → Housekeeping → Available.
FHIR ImagingStudy resources, radiology order workflow, Orthanc PACS integration via DICOMweb (WADO-RS, STOW-RS, QIDO-RS), and OHIF Viewer 3 launch links for browser-based DICOM viewing.
How it works
JamEMR's clinical workflow is a continuous chain of FHIR resources. Every action creates or updates a resource that is immediately queryable, auditable, and interoperable.
Patient resource with demographics, MRN as identifier, blood group and emergency contacts as extensions. Instantly searchable by name, MRN, or any FHIR search parameter.Appointment resource is created and a token assigned. Check-in sets status to arrived. The TV display at /queue/display/ updates in real time — no auth required, for lobby screens.Observation resources with LOINC codes. VitalsSavedEvent fires asynchronously. NEWS2Calculator computes the NEWS2 score (0–20) and stores a RiskAssessment.MedicationRequest is created. MedicationSavedEvent fires. DrugAllergyChecker runs three-level matching. A DetectedIssue is stored and shown as a banner on the chart if a conflict is found.Invoice with ChargeItemDefinition line items. A Claim is generated with pre-tax values. The insurer's remittance creates a ClaimResponse. reconcileInvoice() marks the invoice balanced.Dhis2ExportService POSTs a dataValueSet JSON to your DHIS2 instance.Technical architecture
Every architectural choice in JamEMR is deliberate and traceable — from storage layer to event bus to security model. Here are the decisions that matter most in a clinical system.
reporting schema via @Qualifier("reportingTx") — zero contention with the clinical FHIR server under loadpackage-info.java declaring allowedDependenciesModularStructureTest.verifiesModularStructure() fails the Maven build on any boundary violation — no silent couplinginternal/ sub-packages — structurally inaccessible across module boundaries@ConditionalOnProperty on every feature-flagged module — unused modules add zero startup costCoverage.payor[] references an Organization resource — no separate insurer entity or custom tableClaim.item[].net stores pre-tax subtotals — insurers don't pay VAT or GSTClaimResponseService.reconcileInvoice() is idempotent — safe to call more than once without side effectspatientOwes > 0 after adjudication, the Invoice remains issued for cash collectionX-Frame-Options: DENY, Referrer-Policy: strict-origin@ControllerAdvice strips HAPI server URLs and JDBC strings from all error responses before they reach the browserPOST-only and CSRF-protected — prevents link-based or crawled data loss/health and /info only — all introspection endpoints are inaccessibleCriticalResultEvent, VitalsSavedEvent (triggers NEWS2 calculator), MedicationSavedEvent (triggers drug-allergy checker), StdDiagnosisConfirmedEvent (triggers contact tracing), PregnancyRegisteredEvent, EncounterCreatedEvent, PatientCreatedEvent. Each is a typed Java record — no stringly-typed payloads, no runtime class-cast surprises.
Quick start
Docker Compose launches HAPI FHIR JPA, Orthanc PACS, OHIF Viewer 3, and the JamEMR app — all networked, all configured, all ready.
SMART on FHIR
Not a subset, not "mostly compliant." Every PKCE parameter, every RS256 claim, every token-refresh rule — implemented to spec.
GET /smart/launch?iss=&launch=. The EMR validates ISS against the SMART discovery document (cached per-ISS), builds a PKCE pair with a 128-character code_verifier at RFC 7636 maximum length (derived from 96 bytes of secure random input) and S256 challenge, then redirects to the EHR authorize endpoint with a state nonce for CSRF protection.DefaultJWTProcessor with RemoteJWKSet against the EHR's JWKS endpoint. Signature, expiry, issuer, audience, and nonce all verified. Full RFC 7517 key rotation support.SmartSecurityFilter populates the Spring SecurityContext on every request. TokenRefreshFilter proactively refreshes tokens on /api/** routes 120 seconds before expiry — no expired-token errors surfacing to clinicians mid-workflow.Technology stack
Every dependency is a deliberate choice — maintained by large organisations, widely deployed in healthcare, and stable enough to build a clinical system on.
National alignment
Configure once for your country's reporting standards and interoperability requirements. JamEMR adapts to local health information systems, regulatory frameworks, and disease surveillance programmes — without customisation work.
dataValueSet JSON payload. Supply your facility's organisation unit UID and data element UIDs once — the ETL handles OPD, malaria, TB, NCD, maternal health, and EPI indicator aggregation automatically on a nightly schedule or manual trigger.categoryOptionCombo — the same UIDs used across all PEPFAR-supported programmes worldwide. No additional mapping required; deploy and start reporting on day one.:8090/fhir directly using standard search parameters. No custom integration work required to connect to FHIR-based national data repositories.Coverage, Claim, and ClaimResponse — maps directly to the claims workflows used by national health insurance schemes worldwide. Configure your scheme's plan catalogue, copay rules, and adjudication logic once. The same workflow handles both public insurance schemes and private insurers without any structural changes.Platform capabilities
A complete, production-grade clinical platform — every feature engineered to FHIR R4 spec, not bolted on afterward.
:8090/fhir from day one.Coverage + InsurancePlan catalogue. Phase 2: Claim generation from Invoice with pre-tax line items and duplicate-claim guard. Phase 3: ClaimResponse adjudication with automatic invoice reconciliation and gap invoicing.Questionnaire + QuestionnaireResponse. All FHIR item types, group nesting, enableWhen conditional logic, LOINC codes per item. No Java required.DocumentReference resources with LOINC codes 57833-6 (prescription) and 34133-9 (summary of episode note). Every printable document is also a queryable FHIR resource.MedicationRequest save via MedicationSavedEvent. Stores a DetectedIssue on conflict.Observation save via VitalsSavedEvent. Scores respiratory rate, SpO₂, systolic BP, heart rate, temperature, and consciousness (AVPU). Stores a FHIR RiskAssessment and logs a CDS audit event on elevated scores.AuditEvent asynchronously via @Async("taskExecutor"). Audit writes never block the HTTP request thread. AuditEvent resources use ATNA-aligned agent, source, entity, and outcome structure./queue/display/ — no authentication required, designed for lobby screens.EpisodeOfCare), viral load and CD4 trend observations, WHO clinical staging (I–IV), regimen prescribing and switching (WHO lines 1A–3A). All routes require ROLE_HIV_PROVIDER enforced at the service layer — protection holds regardless of security mode.Location-based bed management, admissions via EpisodeOfCare, SOAP ward-round notes with inline vitals, patient transfer, and discharge with disposition coding. Bed lifecycle: Available → Occupied → Housekeeping → Available.Cache-Control: no-store on all /std/** responses, and ICD-10 A50–A64 filtered from general condition lists.ImagingStudy resources, radiology order workflow via ServiceRequest, Orthanc PACS integration via DICOMweb (WADO-RS, STOW-RS, QIDO-RS), and OHIF Viewer 3 launch links for browser-based DICOM viewing — no plugin, no install.dataValueSet JSON directly to any DHIS2 v2.36+ instance, or produces an HMIS CSV for manual upload.categoryOptionCombo. No country-specific mapping required — UIDs are standardised across all PEPFAR programmes.package-info.java declaring allowedDependencies. ModularStructureTest.verifiesModularStructure() fails the Maven build on any violation. Feature-flagged with @ConditionalOnProperty — unused modules add zero startup cost.VitalsSavedEvent, MedicationSavedEvent, StdDiagnosisConfirmedEvent, PregnancyRegisteredEvent, EncounterCreatedEvent, PatientCreatedEvent, CriticalResultEvent. Each is a typed Java record — no stringly-typed payloads. Modules communicate without cross-module imports.@ControllerAdvice strips HAPI URLs and JDBC strings from error responses. Patient deactivation is POST-only (CSRF-protected). Actuator exposes only /health and /info.CompletableFuture, results cached for 60 seconds with a 200-entry maximum. Bounded eviction prevents unbounded memory growth. Dashboard page loads are consistently fast even on deployments with tens of thousands of patients.docker compose up -d launches JamEMR, HAPI FHIR JPA on PostgreSQL, Orthanc PACS, and OHIF Viewer 3 — all networked, all configured, ready in under 90 seconds. All configuration via environment variables. No config files to edit, no manual service wiring.Frequently asked
https://your-fhir-server/fhir with standard FHIR search parameters from day one. No custom adapter work, ever.Coverage (insurer, policy number, copay/deductible). Phase 2: Generate a Claim from the issued Invoice — pre-tax line items map to Claim.item[], 5 claim-tracking extensions are written back to the Invoice so billing and insurance modules stay independent. Phase 3: When the insurer's Remittance Advice arrives, record a ClaimResponse. Click "Reconcile Invoice" to set insuranceCovered, update patientOwes, and mark the invoice balanced.DHIS2_URL, DHIS2_USERNAME, DHIS2_PASSWORD, and DHIS2_ORG_UNIT. Then one property per indicator mapping your data element UIDs. PEPFAR DATIM UIDs (TX_CURR, TX_NEW, HTS_TST, HTS_POS) are pre-configured and don't vary by country. In download-only mode you still get a JSON dataValueSet and HMIS CSV for manual upload.com.emr.fhir.yourmodule, add a package-info.java with @ApplicationModule(allowedDependencies = {"core"}), annotate your service with @ConditionalOnProperty, and add the flag to Docker Compose. The Modulith architecture test verifies your boundary declarations on every build. Subscribe to existing clinical events without coupling to any other module's internal classes.Support tiers
Community support is free and permanent. Structured support is available for clinics and governments that need deployment guarantees.