
Clinical Decision Support Tools and Examples: A Builder's Guide
What clinical decision support tools exist, how they work in Epic, Oracle Health and OpenEMR, why alert fatigue happens, and how to build CDS with CDS Hooks, FHIR and CQL.
October 30, 2026
OpenMRS is a Java-based, web-based electronic medical record system and the open source community that maintains it. It was built for clinics and hospitals in low-resource settings, and that origin still shapes how it works: it runs on a laptop or a server, it assumes connectivity is unreliable, and it stores clinical data in a way that implementers can reshape without touching the database.
The project started in 2004 in two places at once. At the AMPATH HIV program in Eldoret, Kenya, patient volumes had outgrown the Microsoft Access databases staff were using, and Burke Mamlin and Paul Biondich from the Regenstrief Institute were asked to help. At the same time, Partners In Health had built a web-based record system for drug-resistant TB in Peru and HIV in rural Haiti, and was worried about maintaining it as they expanded into Rwanda, Lesotho and Malawi. The two groups met at the MedInfo conference in September 2004 and agreed to build one system together. OpenMRS first went live at AMPATH in February 2006 and in Rwinkwavu, Rwanda, in August the same year.
The early systems were HIV-specific, but the team decided from the start that a vertical HIV tool would be a mistake, because patients with HIV also have everything else. OpenMRS was designed as a generic medical record system that captures observations, encounters and notes for any program.
Twenty years on, the scale is large but hard to pin down, because nobody has to register an installation. Based on implementer self-reporting, OpenMRS says it runs in production in 80+ countries, at 8,100+ sites, for 22+ million patients. Most of those implementations are run by local, in-country organisations, often as country distributions such as KenyaEMR, UgandaEMR and eSaude in Mozambique. Ministries of health, PEPFAR-funded HIV programs, the ICRC, teaching hospitals and research projects all appear on the list.
The community is the other half of the project. Regenstrief, Partners In Health, AMPATH and Mekom Solutions still hold leadership roles, and development happens in public on GitHub, Slack and the talk.openmrs.org forum. OpenMRS has run Google Summer of Code projects for years, which is where several of its FHIR and SMART on FHIR pieces came from.
The thing that makes OpenMRS different from a typical EHR is that the database does not know what a blood pressure is. Clinical data is stored in an entity-attribute-value model: the entity is a patient or encounter, the attribute is a concept (the question, such as “temperature”), and the value is the answer. Every observation references a concept, and all concepts live in the concept dictionary.
This is why an implementer can add a new program, a new lab test or a new screening form without a schema migration. It is also why the concept dictionary needs to be managed carefully, which we come back to in the implementation section. Most implementations do not build their dictionary from scratch. They start from CIEL, the Columbia International eHealth Laboratory dictionary, which ships with mappings to SNOMED CT, LOINC and ICD-10, and add local concepts on top.
Everything above the data layer is a module. The core platform provides the data model, a Java API and a REST API. Modules add the rest: the REST web services module, the FHIR2 module, ID generation, reporting, appointment scheduling, address hierarchy and so on. Modules are packaged as .omod files and can be installed without changing core code, so an implementation is really a particular set of modules plus a concept dictionary plus forms. OpenMRS calls that packaged set a distribution.

The frontend has been rebuilt twice. The original 1.x reference application used Java Server Pages and server-side rendering. The 2.x reference application (2011) replaced that with a custom UI framework built on Spring MVC and Groovy Server Pages, which was quicker to develop in but was specific to OpenMRS and became hard to hire for. Bahmni, which arrived in 2016, took a different route again with an AngularJS frontend. The result was that organisations could not share frontend work because they did not share a frontend technology.
OpenMRS 3, usually written O3, is the fix for that. The frontend is a set of microfrontends on single-spa, written mostly in React and TypeScript, styled with IBM’s Carbon Design System, and talking to the backend over the REST and FHIR APIs. An app shell coordinates everything and each feature (patient search, the patient chart, registration, forms) is its own frontend module in its own repository. An implementation can swap out or configure a module without forking the whole UI. The backend is unchanged: O3 runs on the same Java platform and the same concept dictionary as 2.x.

O3 is in production. OpenMRS’s own tally, built from implementer self-reporting, has facilities running O3 going from 13 in September 2023 to 3,006 in March 2025, across 35 countries and 11 implementing organisations.
OpenMRS is a Java web application with a MySQL or MariaDB database behind it. The reference application ships as Docker images with a Docker Compose file, which is the quickest way to get a working instance and the way most new implementations are stood up. Older deployments run the .war file directly on Tomcat. Larger national programs run it on Kubernetes or on local servers in each facility with a sync layer between them, which the offline section below covers.
OpenMRS does not store data as FHIR. FHIR support comes from the FHIR2 module, which is a translation layer: it maps OpenMRS’s concept-based data model onto FHIR resources and exposes a FHIR REST API. The module is bundled with the O3 reference application and can be added to any 2.x distribution. The O3 frontend itself uses it, so on an O3 instance the FHIR API is not an optional add-on, it is part of how the UI works.
The module serves FHIR R4 and DSTU3 at the same time. Endpoints live under /openmrs/ws/fhir2/R4/ and /openmrs/ws/fhir2/R3/, and the CapabilityStatement at /R4/metadata tells you exactly what a given instance supports. The OpenMRS FHIR implementation guide lists 17 resource types: Patient, Person, Practitioner, RelatedPerson, Encounter, Observation, Condition, AllergyIntolerance, DiagnosticReport, Medication, MedicationRequest, MedicationDispense, ServiceRequest, Immunization, Task, Group and Location. The module source adds read-only EpisodeOfCare and ValueSet on top of those.
A few things to know before you build against it:
The bigger constraint is terminology. FHIR resources coming out of OpenMRS carry whatever codes the concept dictionary has. If your dictionary is CIEL-based, observations and conditions will have SNOMED CT, LOINC and ICD-10 mappings where CIEL provides them. If it is a home-grown dictionary, you get OpenMRS concept UUIDs and nothing an external system can interpret. Even the O3 reference application’s own Weight (kg) concept maps only to CIEL, PIH and AMPATH, so the weight observations it produces carry a CIEL code but no LOINC code. Most of the pain in OpenMRS FHIR projects is dictionary work.

SMART on FHIR is not production-ready out of the box. OpenMRS has worked on it through Google Summer of Code since 2017, and the 2021 project brief was frank that earlier attempts had not gotten things production-ready. The current approach pairs OpenMRS with Keycloak as the authorisation server, using three pieces: the openmrs-module-smartonfhir module, a Keycloak plugin that adds the SMART extensions to OAuth2, and a second Keycloak plugin that reads OpenMRS’s user table. The setup is documented step by step and supports both EHR launch and standalone launch, but you are assembling it yourself rather than switching it on.
OpenMRS also reports that hundreds of sites use the FHIR API today, against thousands of sites overall, which is a fair picture of where things stand: available, used in real integrations, and still a minority of deployments.
There are three normal starting points. Docker is the default for a new implementation: pull the O3 reference application images, run Docker Compose, and you have a working instance with demo data in a few minutes. The OpenMRS SDK is a Maven-based tool for developers who are writing modules or frontend code and need a local server they can rebuild quickly. Bahmni is the third option, and it is a different product rather than an install method.
The O3 reference application repository ships a Docker Compose file with four containers: a MariaDB database, the Java backend, an nginx container serving the frontend, and a reverse proxy in front of both. docker compose up brings up a demo instance at localhost/openmrs/spa. For production you swap the demo metadata for your own Initializer configuration and point the backend at a managed database, but the same compose file is the starting point.
The SDK is a Maven plugin. mvn openmrs-sdk:setup walks you through choosing a server ID, a distribution (including the O3 distribution) and a database, then mvn openmrs-sdk:run starts it. It is the right tool if you are writing backend modules or frontend code and want to rebuild and restart without rebuilding a container image. It needs Java, Maven and a MySQL instance, and it is a developer tool rather than a deployment method.
Bahmni was started by Thoughtworks in 2012 for Jan Swasthya Sahyog, a rural hospital in Bilaspur, Chhattisgarh, India, and has been governed by the Bahmni Coalition since 2017. It packages OpenMRS with Odoo, OpenELIS and dcm4chee into one hospital information system: OpenMRS for the clinical record, Odoo for billing and inventory, OpenELIS for the lab, dcm4chee as the PACS. Integration between them runs over Atom feeds. If you need inpatient, billing and lab workflows on day one, Bahmni gives you that. The trade-off is that you inherit four systems and an AngularJS frontend that is not O3, so you are not on the microfrontend track.
Whichever install route you take, the same four decisions follow, and they matter more than the software choice. National programs that run well have usually spent more time on these than on OpenMRS itself.
The single decision that most shapes an OpenMRS implementation is how the concept dictionary is managed, and it has to be made before forms are built, because every form field references a concept. The usual advice holds up: start from CIEL rather than inventing concepts, add local concepts only when CIEL has no match, and give one person or team ownership of the dictionary with a review step for additions. Implementations that let every form builder create concepts end up with five versions of “weight” and no way to report across them, and no clean FHIR output either.
Forms are where clinicians spend their time, and in O3 they are built with the form builder and stored as JSON schemas against concepts. The practical rules are the ones that apply to any clinical system: match the paper form or the actual workflow the clinic already follows, keep required fields to what is needed for the program’s reporting, and support the local language. OpenMRS has a role and privilege model that is granular enough to separate registration clerks, nurses, clinicians, pharmacy and lab staff, and administrators. Set it up before go-live rather than running everyone as admin and tightening later.
Many OpenMRS sites have intermittent power and no reliable internet. The pattern that works is a local server in the facility, so the clinic keeps running when the connection drops, and a synchronisation layer that pushes data to a district or national instance when it comes back. OpenMRS has had sync modules for this, and several national programs run their own. O3 runs without internet on a local device or facility LAN, and as of mid-2024 the community was adding handling for flaky LAN connections. Earlier work on an offline tablet mode for community health workers is no longer maintained, so do not plan on that. Plan for sync at the start, because retrofitting it onto a design that assumed a single central database is painful.
The failures are rarely software failures. They are an unmanaged concept dictionary, forms designed by the IT team rather than with the clinicians who will use them, no plan for power and connectivity, no plan for how data gets out to the national reporting system, and training that stops at go-live.
The two get compared because both are open source and both have “open” in the name, but they were built for different buyers and it is rarely a close call.
OpenEMR is a practice management system. It bundles charting, scheduling, billing, claims and patient portal in one PHP application, and it holds ONC Ambulatory EHR Certification, renewed for OpenEMR 8 in January 2026. Its FHIR API covers US Core 4.0.0 with SMART on FHIR and bulk export, because US certification requires it. That makes it the obvious choice for a clinic in the United States that bills insurers and needs certified software. We have a separate guide to OpenEMR that goes into the setup and FHIR details.
OpenMRS is a clinical record platform for public health programs. It is a Java application built around a concept dictionary, which lets a ministry of health define a national HIV or TB program’s data set once and roll it out to hundreds of facilities. Its FHIR API comes from the FHIR2 module, which covers 17 core resources but has no Organization resource and no FHIR-based ordering. It has no billing or claims module in core (Bahmni adds Odoo for that) and no US certification. In their place it offers local deployment that keeps working without internet, country distributions such as KenyaEMR and UgandaEMR, and a community mostly running the same kind of program.
So: a private practice or clinic network in the US, or anywhere that needs billing and scheduling as the core product, should look at OpenEMR. A public health program, an NGO, a ministry of health, or a research project in a low-resource setting should look at OpenMRS, and probably at Bahmni if hospital operations are in scope. On FHIR specifically, OpenEMR’s implementation is further along today because regulation forced it; OpenMRS’s is usable but you should expect to do dictionary work to get clean coded output.
An OpenMRS instance almost never stands alone. The common integrations are the same ones every public health program needs.
DHIS2 is an open source health reporting platform built at the University of Oslo, used by ministries of health in 75+ countries. In most countries where OpenMRS runs, it is the national aggregate reporting system, so facility-level OpenMRS data has to be summarised into DHIS2 indicators. The DHIS2 Connector module does this directly: it takes a Period Indicator Report from the OpenMRS reporting module, maps it to a DHIS2 data set and posts it on a daily, weekly or monthly schedule. Larger programs route the same data through an integration layer such as OpenHIM or OpenFn instead. The important design point is that this is aggregate reporting, not record exchange: DHIS2 wants counts per facility per month, not patient records.
Lab integration is the other near-universal one. OpenELIS is the most common partner, both inside Bahmni and in standalone OpenMRS deployments, and the Lab on FHIR module implements the OpenHIE laboratory workflow for exactly this. It sends each new order to the lab as a FHIR bundle containing a Task and a ServiceRequest, then polls the lab for completed Tasks and pulls back the DiagnosticReport and Observations. The same pattern applies to national lab systems and hospital LIS products that speak FHIR.
For record exchange with a central store, the OpenMRS wiki documents connecting to a shared health record and to a national client registry over FHIR, and the Client Registry module handles patient search and registration against a FHIR-based client registry using the IHE PIX cross-reference transaction. It depends on the FHIR2 module. This is the integration that matters if a country is building a national FHIR repository and wants facility EMRs to contribute to it.
Mobile apps for community health workers and home visits usually talk to OpenMRS over the REST API or the FHIR API, depending on when they were built. The FHIR API is the better choice for anything new, because the app can then work against any other FHIR server without a rewrite, and because O3’s own frontend uses the same endpoints so they are kept working.
OpenMRS has been in production for twenty years, and it has lasted by being changeable at the data model rather than by being feature-complete. The work ahead for most implementations is getting data out of it cleanly, into national FHIR repositories, lab systems and reporting tools, which is dictionary and integration work more than EHR work.
If you are planning an OpenMRS deployment or a FHIR integration around one and want a second opinion on the design, get in touch.
Yes. It is released under the Mozilla Public License 2.0 with a healthcare disclaimer, and there are no licence fees. Costs are hosting, implementation and support.
Yes, through the FHIR2 module, which serves FHIR R4 and DSTU3 and maps 17 resource types. It is bundled with OpenMRS 3. Coverage is not complete, and the quality of coded output depends on your concept dictionary.
Bahmni is a hospital information system built on top of OpenMRS. It adds Odoo for billing and inventory, OpenELIS for the lab and dcm4chee for imaging, with its own frontend. OpenMRS on its own is the clinical record platform.
OpenMRS 3 (O3) is the current reference application. It replaces the older server-rendered UI with React microfrontends on single-spa, on the same Java backend. By March 2025 OpenMRS counted just over 3,000 facilities running it in production.
Yes. The usual setup is a local server per facility with synchronisation to a central instance, and the O3 frontend has offline support for registration and forms on tablets.
OpenEMR for a clinic that needs billing, scheduling and US ONC certification. OpenMRS for public health programs, NGOs and ministries of health, especially where connectivity is poor and the data set is defined at program or national level.

What clinical decision support tools exist, how they work in Epic, Oracle Health and OpenEMR, why alert fatigue happens, and how to build CDS with CDS Hooks, FHIR and CQL.

Build vs. buy for the CMS-0057-F prior authorization API. What each path costs in people and time, what products don’t cover, and which we recommend.

150 GB of hospital data was enough to make Postgres hang for 50 minutes. Here’s how we rebuilt SPARSH’s analytics pipeline to handle it.
No comments yet. Be the first to comment!