What an OpenEMR migration involves
An OpenEMR migration usually starts from one of two situations. The first is moving patient records from another EHR or practice management system into OpenEMR, which means bringing demographics, encounters, documents and billing history across. The second is moving an existing OpenEMR installation to new hosting, such as a different cloud account, a data center or a rebuilt server. The work is different in each case, but both follow the same four stages: extraction, mapping, validation and cutover. Confirm early which situation applies, because it sets the source systems, the data volume and who needs to sign off.
Extraction pulls data out of the source system in a usable form. For a legacy EHR, that may be a vendor export, a database extract or a bulk interface, and the vendor's documentation determines what is included. For an OpenEMR-to-OpenEMR move, the source is the existing database and the document storage directory. Ask the source vendor what each export contains and what it omits, especially attachments, audit history and scanned documents.
Mapping defines how each source field lands in OpenEMR. Patients, insurance, providers, codes and visit types all need a target, and free-text fields often need a rule for where they go. Validation then checks whether the mapped data is complete and correct, using sample patients and reconciliation counts agreed with the clinical and billing leads before the full load. Cutover is the planned switch: a final extract, a freeze on changes in the old system, the load, verification and a go or no-go decision with a rollback path.
What the work includes
The migration covers five data domains and ends with a defined set of deliverables. Scope is agreed in writing before work starts, and the migration is fixed-scope by default.
Patient demographics
Patient identities, contact details, guarantor links, and identifiers from the source system are extracted, mapped to OpenEMR's patient fields, and checked for duplicates before load. Confirm which identifiers must carry over, how merged or inactive records are handled, and which fields OpenEMR has no equivalent for.
Encounters and clinical documents
Visit records, diagnoses, and the scanned or generated clinical documents linked to them are moved with their relationships intact. Document files need a defined storage location and an access check, since a document that loads without its encounter link is hard to find later. Confirm the source system's export formats and any coded data that must keep its code sets.
Scheduling history
Past and future appointments, provider calendars, and appointment categories are mapped to OpenEMR's scheduling model. Decide early whether historical appointments are loaded for reference or only future bookings are carried over, because that choice drives the volume of data and the validation effort.
Billing history
Charges, payments, insurance records, and claims history are extracted as the source system holds them, then mapped to OpenEMR's billing structures. Open balances and claim status need an explicit rule for what is carried forward and what stays in the archive. Confirm this with your billing lead and payer contracts before mapping starts.
Mapping specification
A written specification records each source field, its OpenEMR target, the transformation applied, and the rule for values with no equivalent. It is the reference for every load script and reconciliation check, so it should be approved by the clinical and billing owners before loads are built.
Load scripts and reconciliation reports
Load scripts or import procedures move each domain in a repeatable order, and reconciliation reports compare record counts and sampled values between source and target after each run. Ask for the reports to show exceptions by domain, so that rejected records can be traced to a cause and a decision.
Signed validation record, cutover runbook and rollback plan
The validation record documents who checked each domain and the result, and it is signed by the client's owners. The cutover runbook sets out the steps, owners, and go or no-go checks for the switch, and the rollback plan defines how the client returns to the source system if acceptance fails. Ask for all three to be reviewed together before cutover.
What drives cost and duration
This table lists the main factors that change migration effort, why each one matters for an OpenEMR move from another EHR, and how to keep each one under control.
| Driver | Why it matters | How to keep it down |
|---|---|---|
| Number of source systems and export formats | Each legacy system has its own extract logic, code sets and data gaps. | Inventory every source early and retire sources that hold no needed data. If OpenEMR is the source, use the FHIR Bulk Data export (NDJSON) for extraction. |
| Volume and quality of historical data | Duplicate patients, orphaned encounters and free-text values slow mapping and cleaning. | Profile the data before scoping and set rules for which records are archived and which are migrated. |
| Billing history depth and insurance payer mapping | Open balances, claims history and payer identifiers must map to OpenEMR billing structures. | Limit history to open balances and recent periods, and confirm the payer list before mapping starts. |
| Scanned documents and attachments | Image and PDF volume drives storage, indexing and any OCR or manual indexing effort. | Agree a document scope, index only what clinicians need, and confirm the storage plan for the documents directory. |
| Custom forms and fee schedules to map | Each custom form or fee schedule needs a field-by-field map and clinical or billing sign-off. | Freeze the form and fee inventory and retire unused forms before the build starts. |
| Number of environments and test cycles | Each trial load and reconciliation pass repeats extraction, mapping and validation work. | Plan a fixed number of trial loads and ask the vendor to state the test cycle count in the quote. |
| Interface or FHIR connections to other systems | Live feeds such as labs, imaging or payers add build, testing and monitoring work. | List every interface at scope time and decide which ones are migrated, rebuilt or retired. |
| User count for validation and training | More reviewers and trainees extend validation cycles and training sessions. | Assign named reviewers per data domain and train users in groups by role. |
| Compliance evidence needed | Assessors may expect migration logs, reconciliation reports and access records as evidence. | Define evidence needs with your assessor early and keep reconciliation outputs from each test cycle. |
Project phases and outputs
The sequence moves from source inventory and a controlled target build to tested loads, business sign-off and a cutover that leaves the old system archived and recoverable.
Inventory the source system and its data
We identify the source EHR or OpenEMR instance, its data domains (demographics, encounters, documents, billing history), volumes, custom fields and interfaces, and who owns each domain. The output is a signed source inventory listing every table or export, its owner, known data quality issues and the systems that read from it.
Build the target OpenEMR environment
We provision OpenEMR 8.x on infrastructure you control with PHP 8.3 or later and a MySQL or MariaDB compatible database, then apply the hardening baseline and access controls. The output is a documented build record with versions, configuration, backup settings and a working non-production instance that the migration team can reach.
Map fields and align code sets
We map each source field to an OpenEMR destination, document transformation rules, and align coded values such as diagnosis, procedure, medication and payer codes to the terminology OpenEMR uses. The output is an approved mapping specification with a rule for every field, including fields that will be dropped or stored as documents.
Extract and transform the data
We extract from the source in a repeatable way, apply the mapping rules in scripts under version control, and record every transformation and exception. The output is a versioned transformation package and an exception log that names each record rejected or changed, with the reason.
Run test loads and reconcile results
We load the transformed data into the target several times, comparing record counts, totals, sampled patient records and document links against the source after each run. The output is a reconciliation report per load showing matched, changed and unresolved records, with each unresolved item assigned to an owner.
Validate with your clinical and billing users
Your clinicians, front-office staff and billing team check scheduled test cases against the source using agreed scripts, and record accept or reject decisions. The output is a signed acceptance record that lists each scenario tested, the result and any open defects with their agreed resolution.
Cut over, go live and archive the source
We freeze the source, run the final load, repeat reconciliation, switch users and interfaces to OpenEMR, and keep the source read-only through an agreed hold period. The output is a go-live record with the final reconciliation results, followed by a documented archive of the source data and a closing report.
What to keep in-house and what to outsource
The table lists each OpenEMR data migration workstream with who usually owns it and the skills it needs, so you can see which parts to keep with your staff and which to hand to a partner.
| Workstream | Usually owned by | Skills required | Keep in-house or outsource |
|---|---|---|---|
| Source data access | Source EHR administrator with migration engineer support | Source system database knowledge, export tooling, vendor export rights | Split: practice confirms access rights, partner runs extraction |
| Field mapping | Migration engineer with practice data steward | OpenEMR schema and data model knowledge, understanding of source field meanings | Outsource the draft, practice approves every mapping |
| Transformation scripting | Migration engineer | Scripting, OpenEMR schema knowledge, handling of code sets and date formats | Usually outsource |
| Billing history reconciliation | Practice billing lead with migration engineer | Billing and claims knowledge, clinical coding literacy, ledger reconciliation | Keep sign-off in-house, partner builds reconciliation reports |
| Document and attachment migration | Migration engineer with practice records manager | File handling, storage layout in the OpenEMR documents directory, HIPAA-aware handling of PHI | Split: partner moves files, practice confirms retention and access |
| Clinical validation | Practice clinicians and clinical staff | Clinical coding literacy, knowledge of charts and workflows, HIPAA-aware handling of PHI | Keep in-house. Clinical sign-off stays with the practice |
| Cutover execution | Partner lead with practice IT and operations | Runbook design, downtime planning, rollback procedures, access to hosting | Shared: partner runs the runbook, practice approves go-live |
| Security and access review | Practice security or compliance lead with partner engineers | HIPAA-aware handling of PHI, OpenEMR access control and hardening knowledge | Keep approval in-house, partner prepares evidence and configuration |
What usually goes wrong
Most OpenEMR migration problems trace back to a small set of predictable gaps in extraction, matching, reconciliation and cutover. Each card names the failure and the control that prevents it.
Incomplete source exports
The old system often exports fewer records than the practice expects, because archived patients, inactive providers or custom fields sit outside the default report. Ask for a written inventory of every domain being extracted, then reconcile record counts per domain against the source before any load begins. Gaps found at this stage are cheap to close.
Duplicate patients from merged records
Practices that have merged charts or run several registration desks often hold the same person under multiple identifiers, with slightly different names or dates of birth. Agree a patient-matching rule set with the practice before loading, including which identifiers win and how ambiguous matches are routed to a human reviewer. Without it, encounters attach to the wrong chart.
Billing balances that do not reconcile
Open balances, payments, adjustments and insurance claims can drift between the source ledger and OpenEMR after load, which creates patient statements that are wrong. Reconcile patient balances and totals per account, and freeze the billing period used for the cutover so the comparison is against a fixed snapshot. Confirm who signs off the variance report.
Lost links between documents and encounters
Scanned notes, lab reports and referral letters can load as orphaned files that no longer sit under the encounter they belonged to. Map each document to its source encounter identifier, then sample records in both systems to confirm the link resolves. Broken links are easy to miss because the file still opens.
Code set and payer mismatches
Diagnosis and procedure codes, medication coding and payer identifiers rarely map one to one between EHRs, so claims and problem lists can load with values that do not match what OpenEMR expects. Build a crosswalk for each code set in use, list unmapped values for clinical review, and confirm payer records against current payer setup before billing resumes.
Unplanned scanned document volume
Legacy practices often hold far more scanned material than anyone counted, and bulk upload can strain storage, indexing and migration windows. Inventory the document store early, estimate size from that inventory, and decide which historical documents migrate and which stay in archive. Confirm storage capacity with your infrastructure team before scheduling loads.
PHI copied into test environments or email
Test loads and reconciliation spreadsheets are often built from production extracts and then shared by email or copied to laptops, which exposes protected health information outside controlled systems. Use masked or synthetic test data for build and rehearsal, restrict extract locations, and set rules for how reconciliation reports are transferred and deleted.
Cutover without a tested rollback
Teams sometimes rehearse the load but never rehearse reverting to the source system, so a failed go-live leaves staff with no working record. Schedule a timed freeze on the source system during final extraction, run at least one full rehearsal, and document the rollback steps and decision owner before go-live. Confirm the rollback window with clinical leads.
How the work changes by starting point
Extraction usually depends on what the source vendor will release, so the first task is confirming the export formats and data sets you can get before mapping begins.
- Export scope: Ask whether the vendor provides clinical, scheduling, billing and document exports, and at what cut-off date.
- Bulk FHIR access: If the vendor exposes FHIR Bulk Data, confirm which resource types are covered and whether they match your mapping plan.
- Validation: Reconcile vendor-supplied counts against source reports, since vendor exports may omit or transform fields.
- Cutover: Confirm the vendor's access window after termination and whether a final delta extract is available.
- Confirm with the vendor: Contract terms on data return, export fees and how long data stays available after account closure.
With no export tooling, your team or a partner writes the extraction against the source schema. Most of the effort shifts from vendor coordination to understanding undocumented tables, codes and attachments.
- Schema discovery: Document tables, keys, status fields and code lists before writing queries, and record which fields are actually populated.
- Extraction: Write repeatable scripts that run against a copy of the source, so every dry run produces the same output.
- Validation effort: Expect the largest validation effort here, especially for coded values, duplicate patients and documents stored as file paths or blobs.
- Cutover: Plan a freeze of source writes followed by a final delta run, and name the owner of the source database during the freeze.
- Confirm with the hosting team: Backup windows, read replica access and whether the source system can be taken offline for extraction.
The data already uses the OpenEMR schema, so the work centers on moving the database, documents directory and configuration intact, then verifying that they still match.
- Version and runtime: Confirm the current release and PHP version against the target, since recent releases require PHP 8.3 or later.
- Database: Confirm the target runs a MySQL or MariaDB compatible database, and test a full restore before cutover.
- Documents and permissions: Copy the documents directory with its ownership and permissions, then confirm the web server blocks direct access to it.
- Container setup: For Docker deployments, check how configuration, sites and documents are mounted, and confirm the setup script is removed after installation.
- Confirm with the hosting team: DNS changes, TLS certificates, backup retention and whether the old environment can stay available for rollback.
A network of clinics usually means several source systems or several OpenEMR sites with overlapping patients. Identity matching and site ownership drive most of the validation effort.
- Patient identity: Decide how duplicate patients across sites are matched and who approves merges before any data loads.
- Facility mapping: Map each site's facilities, providers and schedules so billing and scheduling stay attributable to the correct location.
- Sequencing: Plan site-by-site cutovers around clinical staffing, and decide early whether sites share one instance or run separately.
- Validation: Reconcile patient counts, open encounters and outstanding balances per site, not only across the whole network.
- Confirm with the network team: Connectivity between sites, ownership of the identity provider and whether any site has its own hosting contract.
Without internet access, every package, container image and dependency must be staged inside the network before extraction starts. Transfer and approval steps often set the schedule more than the data work does.
- Staged artifacts: Bring OpenEMR packages, container images, PHP dependencies and any database tooling in through the approved transfer process.
- Extraction location: Run extraction inside the enclave, and confirm how exported files leave it for review, if they must leave at all.
- Validation: Build reconciliation reports that run locally, since external validation services may not be reachable.
- Evidence: Record every transfer, checksum and approval, because auditors and internal reviewers will ask for them later.
- Confirm with the data center team: Transfer procedures, change windows, backup targets and whether the FHIR Bulk Data export can run with no external calls.
What you need to provide
Before migration work starts, the client supplies the inputs that determine whether the mapping can be built correctly. The core items are read access or full exports from the source EHR, a data dictionary or schema documentation that explains how the source stores demographics, encounters, orders and billing, and sample records for each data type, including documents and billing history. Without the schema, mapping is guesswork, and without samples, validation cannot show whether real records survive the move. Ask the source vendor or internal administrators which export formats are available and whether the export is complete or limited to certain record types.
Two named owners are required for decisions that cannot be delegated to the migration team. A clinical owner approves how diagnoses, medications, allergies, encounter types and clinical notes map into OpenEMR's structures. A billing owner approves how payers, fee schedules, claims history and open balances are reconciled, since billing errors surface after cutover and are costly to unwind. Both should be available for mapping reviews and reconciliation sign-off, not only at the start.
The client also provides the target environment. Confirm the hosting location, the PHP version (recent OpenEMR releases require PHP 8.3 or later), and the MySQL- or MariaDB-compatible database version and configuration. Provide a test environment isolated from production so that repeated load and validation runs never touch live patient data. Decide early how historical scanned documents and attachments will be stored, including whether files live on the server's drive, in object storage, or in another document system, and whether they will be encrypted at rest. This decision affects storage sizing and the document directory's access controls.
Finally, name the sign-off owners for cutover and the recipient of the final migration record. Cutover approval should be given in writing by the clinical and billing owners, together with the IT owner responsible for the target system. The final migration record, which lists source extracts, mapping decisions, validation results, reconciliation totals and known exceptions, should go to the client's compliance or privacy lead and to whoever will maintain the system after go-live. Agree on these names and the recipients in the written scope, before extraction begins.
Frequently asked questions
What drives the cost of an OpenEMR migration and can it be quoted fixed-scope?
Yes, most engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts. OpenEMR has no license fee and no paid edition, so the cost is services plus the infrastructure you run. The main drivers are the source system's export options, the number of data domains moving (demographics, encounters, documents, billing), the depth of billing history, how much custom mapping is needed and how many validation rounds your clinical and billing staff will run. Ask the quote to list each data domain, the access method for the source system, test cycles, cutover support and any assumptions it depends on.
How long does moving patient data from another EHR into OpenEMR take?
The timeline depends on the source system's export options, data volume, mapping complexity and the number of validation rounds clinical and billing staff need to sign off. DeployOpen does not publish durations. The timeline is set in the written scope after discovery, when the source data has been profiled. Ask for a phase plan that shows dependencies, the sign-off points for clinical and billing owners, the test cycles and the cutover window, and ask which of these depend on the source vendor's cooperation.
Can our own IT team migrate to OpenEMR without an implementation partner?
Yes, if your team has engineers comfortable with PHP, MySQL or MariaDB, healthcare data formats and the source system's export tools. OpenEMR's FHIR API implements Bulk Data export in NDJSON, which can help with extraction, but you must confirm that the resource types you need are available from your source. Clinical and billing sign-off is required either way. Partners add the most value in discovery, mapping rules, validation scripts and cutover runbooks, so compare those tasks with your team's capacity before deciding.
What must our organization supply before a migration project starts?
Expect to provide access to the source system, either an export, database read access or a supported API, along with its data dictionary and sample extracts. You will also need code sets for diagnoses, procedures and payers, provider and location lists, and named clinical and billing owners who can approve mappings. The target OpenEMR host must run PHP 8.3 or later on a MySQL- or MariaDB-compatible database, and you need a test environment and a cutover window agreed in advance. Confirm each item with your own systems owners before the scope is written.
How is billing history handled when moving from another EHR to OpenEMR?
Billing history moves as financial records tied to patients, encounters and payers, so it is mapped and reconciled rather than loaded as-is. Decide with finance how many years to migrate, which claim statuses to include, and how open balances, payments and adjustments are represented. Validation compares totals and aging per patient and payer against reports from the source system. Some organizations keep read-only archived reports for older history. Confirm which billing and fee sheet records your OpenEMR version can load before the mapping is agreed.
How is patient data protected during extraction and testing?
Extracts stay inside infrastructure you control, and access is limited to named people and documented in the scope. Use HTTPS only, restrict who can reach extract files, and encrypt stored copies. Follow the hardening guidance in the Securing OpenEMR guide, including removing setup scripts after installation and blocking direct web access to the documents directory. Where clinical validation allows, test with de-identified or minimized datasets, and delete working copies at the end of each cycle. Confirm the required controls and retention rules with your privacy and security officers.
How DeployOpen delivers OpenEMR migrations
DeployOpen plans, builds and hands over OpenEMR data migrations inside infrastructure you control, from extraction on the source system through validation and cutover. Each engagement is fixed-scope, with the scope agreed in writing before the work starts.
How we scope
- Written scope lists which source data types move, such as demographics, encounters, documents and billing history.
- Source system inventory records the export formats, data volumes and known data quality issues you can provide.
- Scope names the OpenEMR version, PHP and database targets and the hosting model, such as Docker or a server you manage.
- Scope states who owns clinical data decisions, sign-off on mapping rules and the acceptance criteria for cutover.
How we build
- Field-level mapping documents each source field to its OpenEMR destination, with rules for codes, dates and duplicates.
- Extraction and load scripts run first against copies of the source data, so mapping gaps surface before production.
- Validation checks compare record counts, sampled patient charts and billing totals between source and target after each run.
- Where the source system offers bulk export, OpenEMR's FHIR Bulk Data v1.0 export at system, patient and group level in NDJSON format can inform the extraction design. Confirm feasibility with your source vendor.
How we hand over
- Delivered documentation covers the mapping specification, load procedures, validation results and known exceptions.
- Cutover runbook sets out the freeze window, rollback steps and the order of operations agreed with your team.
- Post-migration reconciliation report records what moved, what was excluded and who approved each exception.
- Knowledge transfer sessions train your administrators to rerun validation and maintain the target environment.
How we support
- Ongoing support, upgrades and continuous testing are available as retainers after cutover.
- Post-cutover support can cover issues found in production data that validation did not catch, under the written scope.
- Retainers can include applying OpenEMR security releases and planning version upgrades, so the system stays current.
- Confirm with us which support responsibilities sit with DeployOpen, your staff and any third-party support vendor you choose.

