What an OpenMRS O3 migration involves
The migration changes the screens, not the core. O3 is a new user-facing frontend built on micro-frontend modules, so moving a 2.x implementation to it replaces how clinicians see and enter data while the Java platform, the database and the patient data model stay in place. The work is therefore concentrated in four places: the form definitions that drive data entry, the custom modules that hook into 2.x extension points, the metadata that the forms and screens depend on, and the cutover plan that moves users from one interface to the other. Before estimating anything, confirm which of these your current system depends on most heavily.
The most common trigger is a 2.x implementation or custom distribution that must move to O3. Legacy HTML forms are the usual first problem, because they do not run in O3 and must be rebuilt in the O3 form schema. Palladium Kenya built a tool to help convert legacy HTML forms, and the community adopted it, but a converted form still needs review by someone who knows the clinical workflow. Custom modules that depend on 2.x extension points need a separate assessment, since each one may need redesign rather than conversion. Ask your current developers to list every custom module, form and report, and mark which ones clinicians use daily.
A third trigger is records arriving from paper or another EMR. In that case the migration includes data reconciliation: mapping source fields to concepts and encounter types, deciding which historical data is loaded and which is archived, and agreeing how duplicate patients are merged. Metadata such as concepts, forms and locations is usually managed through the Initializer approach, so that configuration can be versioned and promoted between environments. Confirm early who owns the concept dictionary, because unresolved concept decisions are a frequent source of delay.
Keep it in-house or bring in a partner. Teams usually keep the work in-house when they already have Java, OpenMRS and clinical informatics skills, and when their custom modules are few and well documented. They usually bring in a partner for form and metadata conversion, data reconciliation and cutover planning, especially when clinical staff cannot release time for conversion review. Whichever route you take, ask for the written scope to name the forms, modules, data sources and the cutover approach.
What the work includes and what you receive
Each package below ends with a document, artifact or test result that your team keeps and can run without us. The scope of each package is agreed in writing before work starts, and the depth of each one depends on how much custom code and legacy data your current system holds.
2.x inventory and migration assessment
We catalog the forms, concepts, custom modules, reports, integrations and data volumes in your OpenMRS 2.x instance, and note which Platform and module versions they depend on. The assessment separates what moves unchanged from what needs rework, so you can see the size of each remaining package before committing to the build. You keep the inventory and the assessment report.
Forms conversion to the O3 schema
We convert legacy HTML forms to the O3 form schema, starting with the community converter that Palladium Kenya built and the community adopted. We review each output for the cases the converter does not handle, such as complex repeating sections, custom widgets and obs-group logic, and rebuild those by hand. You keep the converted forms, a list of manually rebuilt forms, and the rebuild notes.
Metadata packaging with Initializer
We export concepts, forms, encounter types, locations and other metadata into a versioned package that Initializer applies to each environment, so configuration moves through development, test and production the same way. Checking the package against a clean database is the step that catches missing dependencies and ordering problems. You keep the metadata package, the deployment procedure and the version record.
Custom module port or replacement
Each custom module is either ported to the 3.x and Platform APIs in use for your target release or replaced with a supported module or configuration. The decision depends on whether the module's function still exists in O3 and on how much of its logic lives in the database rather than in code. You keep the port or replacement decision record, the code changes and the regression results.
Data import and reconciliation
We map source records from paper registers or another EMR into OpenMRS concepts, patients and encounters, then import them in batches and reconcile counts and sample values against the source. Duplicate patient detection and identifier rules are agreed with your data owners before the first load. You keep the mapping specification, import logs and the reconciliation report.
Phased cutover runbook
The runbook sets out the order of freeze, final sync, metadata deployment, verification and go-live for each site or department, with a rollback point at each stage. We rehearse it in a non-production environment so the timing and the owners of each step are known before production. You keep the runbook, the rehearsal record and the rollback procedure.
Test evidence and handover documentation
Test cases cover forms, metadata loads, module behavior and data checks, with the results recorded against the versions tested. Handover documentation explains how to operate, back up and upgrade the O3 environment and which items belong to your team after go-live. You keep the test evidence, the operations guide and the support hand-off notes.
What drives cost and duration
Each row names a factor that changes the effort of an OpenMRS 2.x to O3 migration, why it matters, and how to keep it manageable.
| Driver | Why it matters | How to keep it down |
|---|---|---|
| Legacy HTML forms | Each 2.x HTML form must be rebuilt or converted for the O3 form schema, and complex forms with calculated fields, obs groups or custom widgets take longer to verify than simple ones. | Inventory every form and mark it as retire, convert or rebuild before scoping. Retire forms nobody uses and convert simple ones with the community tool. |
| Custom modules and 2.x API use | Modules written against 2.x APIs may not load or behave correctly on the current platform, so each one needs review, rewriting or replacement. | List modules with their owners and usage. Replace modules that duplicate standard functions, and confirm API compatibility for the target Platform version early. |
| Concept dictionary and metadata quality | Duplicate concepts, inconsistent names and unmapped codes make forms, reports and integrations slower to build and harder to validate. Initializer configuration depends on clean metadata. | Audit concepts before migration, merge duplicates, map to reference terminologies where needed, and manage metadata in version-controlled Initializer files. |
| Source and condition of paper or external EMR data | Paper records need transcription and validation, and data from another EMR needs field mapping, deduplication and quality checks that vary by source system. | Confirm what data is in scope, define a minimum dataset, and sample the source early to estimate cleaning effort. Ask the vendor or site staff for data dictionaries. |
| Number of sites and phasing order | Each site adds configuration, training, connectivity and cutover work, and a phased order determines how long old and new systems run side by side. | Pilot at one site, reuse one configuration and cutover runbook across sites, and agree the phasing order in writing before the build starts. |
| Integrations (FHIR2, SMART on FHIR, OAuth2 Login) | Each enabled module adds configuration, test cases and identity mapping, and changes to the FHIR or authentication layer can affect apps that depend on them. | Enable only the integrations in scope for the first release, document their configuration, and test them in a staging environment that mirrors production. |
| Database engine (MySQL, MariaDB or PostgreSQL) | The OpenMRS core supports MySQL, MariaDB and PostgreSQL, and the choice affects migration scripts, backup tooling, the O3 Docker Compose setup (which uses MariaDB) and operator skills. | Choose the engine your team already operates where the target distribution supports it, and confirm the supported versions in the release notes before planning. |
| Deployment form (WAR on Tomcat or Docker Compose) | A WAR deployment on Tomcat and the O3 Docker Compose stack differ in how modules, frontend assets, SSL and upgrades are handled, so moving between them adds rework. | Decide the deployment form before configuration starts, and build the environment from versioned infrastructure code so later changes are repeatable. |
| Number of environments kept in parallel | Each extra environment for development, testing, training or staging needs its own data refresh, configuration sync and maintenance, and parallel legacy systems add cutover risk. | Limit environments to those the test plan needs, refresh test data on a fixed schedule, and retire legacy environments once cutover is signed off. |
Project phases and outputs
The sequence moves OpenMRS 2.x records, forms and custom code onto the O3 frontend in controlled steps, with a validated dataset and a pilot before any site cuts over.
Assess forms, modules, metadata and data sources
DeployOpen inventories every legacy HTML form, custom module, concept and metadata set, and source system, including paper records or another EMR where data must be brought in. Your clinical and data leads confirm which forms are still in use. The output is a written inventory with a convertible or manual-rebuild status for each item, and the scope and phase durations are set from that inventory.
Build target architecture and non-production environments
DeployOpen designs the target architecture on infrastructure you control and builds non-production environments from the O3 Reference Application stack, which runs MariaDB, the OpenMRS backend, Nginx services and a gateway through Docker Compose, with optional Certbot for certificates. Hosting, database and TLS decisions are documented. The step closes when a test environment runs the target stack and the migration team can deploy to it repeatably.
Convert forms and metadata with a manual rebuild list
Forms are converted to the O3 form schema where a conversion path exists, and metadata such as concepts and form definitions is brought over through Initializer-based configuration. Every item that cannot be converted automatically is recorded on a documented manual-rebuild list with an owner. The output is the converted configuration in version control and that list, reviewed with your clinical team.
Port or replace custom modules
Each custom module is either ported to the current OpenMRS Platform and tested against it, or replaced with an existing community module or a configuration change. DeployOpen records the decision for each module with the reason. The step closes when every module builds, deploys to the test environment and passes its functional tests.
Import data and reconcile with validation sign-off
Patient, encounter and observation data is extracted, transformed and loaded into the target environment, then reconciled against source counts and sampled records. Discrepancies are logged, fixed at source or in the mapping, and rerun. Your data owners sign off on the validation results in writing before any data is treated as production-ready.
Pilot at one site, then phased cutover
The validated configuration runs at one pilot site with real users under agreed support arrangements, and issues are fixed before wider rollout. Remaining sites then cut over in the sequence your written plan sets. The output is a cutover record per site showing go-live date, data checks and open issues.
Hand over and transfer knowledge
DeployOpen delivers runbooks, configuration repositories, the manual-rebuild list, test records and operational procedures, and trains your platform and clinical support staff. The handover closes when your team has run a documented deployment and recovery task without DeployOpen involvement. Ongoing support and upgrades can be scoped separately as a retainer.
Which parts to keep in-house and which to outsource
This table shows who usually owns each part of an OpenMRS 2.x to O3 migration and which skills each part needs, so you can split the work between your team and a partner.
| Work part | Usual owner | Skills needed |
|---|---|---|
| Clinical content and form design | In-house, with clinical leads | Clinical workflow knowledge, decisions on fields, validation rules and order of entry |
| Metadata and concept mapping | Shared between in-house informatics and partner | Concept dictionary knowledge, terminology standards and OpenMRS metadata tooling such as Initializer |
| Converter runs and manual form rebuilds | Often outsourced to a partner | O3 form schema, HTML form conversion and manual rebuild of forms the converter cannot handle |
| Java and Maven module ports | Outsourced unless an in-house Java team exists | Java, Maven and OpenMRS module APIs, plus testing against the target platform version |
| Data mapping and reconciliation | Shared with the data owner | Source database knowledge, record counts and patient-level reconciliation checks |
| Environment and deployment setup | Either side, with container or Tomcat skills | Docker Compose or Tomcat with MySQL, MariaDB or PostgreSQL, TLS and backup configuration |
| Testing and sign-off | In-house clinical validation, with partner test scripts | Clinical acceptance criteria, user acceptance testing and documented sign-off |
| Cutover governance | In-house sponsor, with partner runbook | Project sponsorship, go/no-go decisions, rollback planning and site communication |
What goes wrong and how to prevent it
Most OpenMRS 2.x to O3 migrations stall for predictable reasons. The cards below name each failure point and the preventive step to put in the plan before build work starts.
Forms that need rebuilding
Not every legacy HTML form converts cleanly to the O3 form schema, and some depend on behavior the converter does not reproduce. Build a conversion inventory that lists each form, its concepts, obs groups, rules and custom widgets, then tag each one as convert, rebuild or retire before estimating the work.
Custom modules tied to 2.x behavior
Custom modules may call 2.x APIs, extend controllers or rely on behavior that changes in later Platform and O3 releases. Pin the Platform and module versions in the plan, check each module against the target release, and ask the implementer which APIs it uses and which of them are deprecated.
Metadata that drifts between environments
Concepts, forms, locations and privileges edited directly in production never reach development, so test results stop matching live behavior. Keep metadata in a version-controlled package, load it with Initializer, and block manual edits in production so each environment is built from the same source.
Legacy records with quality problems
Paper or older electronic records often hold duplicate patients, missing identifiers, inconsistent coded values and free-text entries that do not map to concepts. Run a data validation sample against agreed rules before any bulk load, and record who signs off on the rejected and corrected rows.
Two systems running without rules
When staff enter data in both the old and new systems without written rules, records diverge and nobody knows which copy is authoritative. Define which system is the source for each data type and each site, set a date when entry stops in the old system, and train staff on that rule before go-live.
Integrations and reports that break
Reports, data exports, FHIR consumers and other integrations often query screens, form fields or database structures that change during migration. Inventory every downstream consumer, test each one against the O3 build, and agree with its owner how changes to fields or concepts will be communicated.
Cutover without a rollback point
A cutover plan that has no defined rollback point leaves teams stuck when validation fails late on the day. Write the cutover and rollback plan with named decision owners, the last point at which rollback is still practical, the backup that restores the 2.x state, and the checks that trigger each decision.
How the work changes by starting point
A standard 2.x deployment usually runs the Platform as a WAR file on Apache Tomcat with MySQL, MariaDB or PostgreSQL, using the stock or lightly configured metadata. The migration here is mostly about the user-facing layer, so the work centers on forms and configuration rather than moving records.
- Scope: inventory existing forms, custom screens and configured metadata, then decide which move to O3 and which are retired.
- Data work: little or no record movement, but confirm the database version and schema are compatible with the target Platform before any cutover plan is set.
- Environments to rebuild: a parallel O3 stack, typically the Docker Compose setup with MariaDB, the backend, Nginx frontend and gateway, for testing against a copy of production data.
- Deciding questions: how many HTML forms are in use, whether any depend on Platform-only features, and whether the team can run a parallel build for the cutover window.
Confirm the supported database and Tomcat combinations for your target version with your own environment and the OpenMRS documentation.
A custom distribution adds modules, metadata packages and configuration on top of the OpenMRS core, so every customization must be reviewed for compatibility with O3. Some of it will move cleanly, and some will need to be rebuilt or dropped.
- Scope: list each custom module, its owner and whether it provides a user interface, an API or back-end logic only.
- Data work: map custom concepts, forms and metadata into the target distribution, and plan how Initializer-managed metadata is versioned across environments.
- Environments to rebuild: the build pipeline, the distribution's own test environment and any integration endpoints the custom modules call.
- Deciding questions: which modules have no maintained equivalent, who owns the distribution code after handover, and whether the national or implementer distribution already has an O3 path.
Confirm module compatibility against the specific module versions in your distribution.
Records that exist only on paper add a data capture project to the migration. The system design matters less here than the process for transcribing, verifying and recording who entered each value.
- Scope: decide which paper records are migrated (active patients, recent encounters, or full history) and which stay in archive.
- Data work: design a capture form that matches the target concepts, define double-entry or verification rules, and set a patient identifier strategy before entry starts.
- Environments to rebuild: a training or data-entry instance with the same forms and concept dictionary as production, so staff practice on the real structure.
- Deciding questions: the volume of paper records, the staff available for entry, how duplicate patients will be detected, and what audit evidence the clinical governance process requires.
Ask for the verification method and error-rate checks in any quote, since these drive effort more than the system build.
Moving from another EMR means extracting, mapping and reconciling data between two different models. The source system's export format, terminology and patient identifiers determine most of the work.
- Scope: define the data domains to move (patients, encounters, observations, orders, medications) and which are summarized rather than migrated.
- Data work: map source codes and fields to OpenMRS concepts, write transformation and load scripts, and reconcile patient matches across both systems.
- Environments to rebuild: a staging Platform instance where test loads run repeatedly, plus a reconciliation report that compares counts and sample records.
- Deciding questions: whether the source vendor provides a complete export, how terminology is coded at source, and whether FHIR or a flat file is the practical extract route.
Confirm the export options and data licensing terms with the source EMR vendor before scoping the load.
When the deployment must stay on-premises or air-gapped, every component, package, container image and metadata source has to be available inside the network. Installation and updates need an offline path, and verification happens without external calls.
- Scope: include an internal artifact process for the Platform WAR or Docker images, database packages, and any module dependencies.
- Data work: keep all migration tooling and data inside the boundary, and avoid cloud-hosted transformation services.
- Environments to rebuild: an internal staging stack that mirrors the air-gapped production network, including the gateway, TLS and certificate handling.
- Deciding questions: how images and packages are transferred across the boundary, who approves them, and whether the Docker Compose setup or the Tomcat WAR path fits your change process.
Confirm the transfer and approval process with your own security team before planning the build.
What you need to provide
Before we can quote an OpenMRS 2.x to O3 migration, we need the source and data inventory that determines how much conversion work exists. The first items are access to the current 2.x platform or custom distribution source, including every custom module and its build configuration, and a copy of the production database with a staging restore we can run against. Without the restore we cannot measure record volumes, duplicate patients or orphaned encounters, so the estimate would rest on guesses about the data.
Next, provide an export of the forms in use and a usage report showing which forms are filled in, how often and at which sites. Forms that nobody has used in years can be retired rather than converted, which changes the workload directly. Also provide the metadata and concept dictionary export, along with a list of custom modules and a named owner for each one. Each module needs a decision: keep, rewrite for the O3 frontend, or drop. Owner names matter because those decisions cannot be made by the implementation team alone.
Third, identify every source of records that sits outside the database, such as paper registers, spreadsheets or another EMR. For each source, name a data owner who can answer questions about its fields, quality and legal custody. Also name a clinical sign-off owner for each converted form. Clinical reviewers, not developers, must confirm that the O3 form still captures what care teams need. Their availability sets the review schedule, so confirm it now.
Finally, confirm hosting and network access for non-production environments, a named cutover sponsor with authority over go or no-go decisions, and the cutover approach. A big bang move and a site-by-site phased cutover need different parallel running, data synchronization and training plans, and they carry different costs. Decide this before scoping, and record it in writing with the sponsor's name, because the choice changes the quote more than almost any other input.
Frequently asked questions
What drives the cost and duration of an OpenMRS O3 migration?
Scope drives both cost and duration more than anything else: the number of legacy forms, custom modules, metadata to map, sites and users to train, and interfaces to rebuild. Cost has two main parts: labor for analysis, build, testing and cutover, and the infrastructure you run in your own environment. Ask for a quote that lists each deliverable, the environments covered, the assumptions about source data quality, and what is excluded. DeployOpen does not publish a price list, so a quote follows from the written scope.
Can our own team run an OpenMRS 2.x to O3 migration without a partner?
Yes, a team with Java, Tomcat or Docker, and MySQL, MariaDB or PostgreSQL experience can attempt it, but much of the work is specific to OpenMRS. The hardest parts without OpenMRS experience are usually concept dictionary and metadata mapping, converting legacy HTML forms to the O3 form schema, checking custom module compatibility, and validating clinical data after load. Assess your team against those four areas before you decide.
Can all of our legacy OpenMRS forms be converted automatically?
Not reliably in every case. The community adopted a tool built by Palladium Kenya, described in an October 2023 OpenMRS blog post, that migrates legacy HTML forms to the O3 form schema. Forms with custom JavaScript, unusual widgets or complex logic typically need manual rebuilding, and forms that depend on custom modules need separate review. Expect every converted form to be checked against current clinical workflows. Ask for a form inventory with a complexity rating before effort is estimated.
Does an OpenMRS O3 migration need a phased cutover?
Often yes, especially for multi-site programs, but the answer depends on whether sites can tolerate downtime and whether O3 covers every workflow in use. A phased cutover moves one site, department or workflow group at a time, keeps the legacy system available for reference, and sets exit criteria before each wave. Plan the sequence, rollback steps, staff training and the period when records exist in both systems, with a named owner for each step.
How is patient data validated after migration to O3?
Validation compares source and target records at several points: record counts per patient, encounter and observation types, sampling of charts reviewed by clinicians, and rule-based checks for mapped concepts and identifiers. Run validation on test loads first, then on each cutover wave. Agree acceptance thresholds and sign-off owners before cutover begins. Confirm the approach with your clinical governance team, because the exact checks depend on your data model and concept dictionary.
Does DeployOpen certify OpenMRS compliance after a migration?
No. DeployOpen does not issue audit reports, attestations or certifications. We prepare systems, configuration, access controls and evidence for compliance assessments, and independent auditors or certification bodies make the determination. Ask your auditor which evidence they need, such as access logs, backup records, change records and migration validation reports, so the migration plan can produce it from the start.
How DeployOpen scopes, delivers and hands over
DeployOpen plans, implements, customizes, documents and supports self-hosted open-source platforms inside your own infrastructure, and the OpenMRS 2.x to O3 migration follows the same written, fixed-scope process. The work runs in the cloud accounts, data centers or air-gapped networks your organization controls.
How we scope
- The written scope lists which 2.x forms, custom modules and metadata move to the O3 frontend, and which stay out.
- We inventory existing HTML forms, concept dictionary use and custom modules so the cutover plan reflects what is actually deployed.
- Engagements are fixed-scope, with deliverables and timelines agreed in writing before any migration work starts.
How we build
- We convert legacy HTML forms to the O3 form schema, using the community Palladium Kenya tool where it fits the form set.
- Metadata moves through Initializer in a versioned, repeatable way so test and production sites stay consistent.
- We test each phase, including custom module behavior, data integrity checks and the phased cutover sequence, before go-live.
How we hand over
- You receive documentation covering the converted forms, metadata configuration, custom module changes and cutover runbook.
- Your team is walked through the deployed stack, including the O3 Docker Compose services, so operations do not depend on us.
- Test evidence, rollback steps and open items are delivered with the handover so your staff can verify the result.
How we support
- Post-cutover support, upgrades and continuous testing are available as retainers, scoped separately from the migration.
- Retainers can cover O3 Reference Application and Platform upgrades, module testing and database change review.
- Confirm response expectations, service levels and support hours in the written retainer scope before you sign.

