Migrating from Primavera P6: a technical guide
What an XER file actually carries
Before you migrate anything, it helps to know exactly what you are moving. An XER is a tab-delimited text file that encodes a set of named tables — %T for the table name, %F for the field list, %R for each row. It is not a database dump; it is a selective export of the tables P6 considers exchangeable. Understanding its boundaries matters more than understanding its contents, because the boundaries are where migrations lose fidelity.
A typical XER from a live programme contains:
- PROJECT — the project row: name, data date, must-finish-by date, scheduling options, and the project-level defaults for activity type, duration type, and percent-complete type.
- TASK — every activity, including milestones (which travel as activities of type
TT_MileorTT_FinMile) and level-of-effort items (TT_LOE). Each row carries the activity’s type, duration type, percent-complete type, physical percent, status, durations in hours, all six date fields (early, late, actual), constraint type and date (primary and secondary), calendar assignment, and float. - TASKPRED — every relationship: predecessor, successor, type (FS, SS, FF, SF), and lag in hours.
- CALENDAR — calendar definitions, packed into a proprietary parenthesised text blob. Weekly patterns, holidays, and closures are all encoded in this single string. Some blobs in the wild fail to parse cleanly.
- PROJWBS — the WBS hierarchy, including each node’s responsible manager (via
obs_id), status, and earned-value settings. - OBS — the organisational breakdown structure, exported whole with its hierarchy.
- SCHEDOPTIONS — one row per project, carrying the lag calendar setting, the progressed-logic mode, the SS-lag basis, the expected-finish flag, the open-ends-critical flag, the total-float basis, and the multiple-float-path parameters.
- ACTVTYPE / ACTVCODE / TASKACTV — activity code definitions, their hierarchical value lists, and the per-activity assignments.
- RSRC / RSRCRATE / TASKRSRC — resources (with effective-dated rates) and their assignments to activities.
- UDFTYPE / UDFVALUE — user-defined fields and their values.
- TASKPROC — activity steps (name, weight, percent, sequence). Present in a minority of real files; most programmes do not use steps.
- TASKNOTE / TASKMEMO / WBSMEMO — notebook entries on activities and WBS nodes.
- TASKDOC / TASKFDBK — document links and field feedback text.
What the XER does not carry
Two absences matter for any migration.
Baselines. A baseline does not travel inside the XER. P6 exports a baseline as a separate project — often as a sibling project row within the same file. If you receive an XER with three PROJECT rows, one is likely the current programme and the others are baselines. Any receiving system needs to recognise this pattern and let you designate which project row is a baseline of which.
The EPS. The enterprise project structure does not export. Each project’s root WBS node points at the EPS node it sat under, but that EPS node does not exist anywhere in the file. You cannot reconstruct the source EPS from an XER; you choose where the imported project lands in your own structure.
What transfers cleanly
The core scheduling model — activities, relationships, calendars, constraints, and the scheduling options that govern how float and logic are computed — transfers with high fidelity. A well-built importer maps these one-to-one:
- Activity types map directly:
TT_Taskto task,TT_Mileto start milestone,TT_FinMileto finish milestone,TT_LOEto level of effort. - All four relationship types (FS, SS, FF, SF) and their lags carry across. A pair of activities connected by both an SS and an FF — the standard overlap idiom — should import as two separate links, not one.
- The nine constraint types (SNET, FNET, SNLT, FNLT, MSO, MFO, SO, FO, ALAP) map one-to-one. Primary and secondary constraints both travel.
- Scheduling options — lag calendar, progressed-logic mode, expected-finish behaviour — should import and apply, not merely display. A programme imported under different scheduling options will compute different dates, and you will spend hours chasing phantom variances.
- Activity codes, their hierarchical value lists, and per-activity assignments transfer as structured data.
- Resources and assignments, including effective-dated rates, travel in
RSRC,RSRCRATE, andTASKRSRC.
Progress state — actual starts, actual finishes, remaining durations, physical percent, suspend and resume dates — also transfers cleanly when the importer treats these as statusing facts rather than discarding them.
Where to watch for drift
Hours to days
XER durations and lags are stored in hours. Converting to days requires dividing by each calendar’s day_hr_cnt (hours per working day). This is not a global constant — a six-day calendar with eight-hour days and a five-day calendar with ten-hour days produce different conversions for the same number of hours.
Watch for: rounding. A 12-hour lag on a calendar with 8-hour days is 1.5 days. Any system that schedules in whole days must round, and whether it rounds up or down affects the computed dates. The import report should total the rounding across the file so you can see the cumulative drift, not discover it activity by activity.
Watch also for which calendar counts the lag. The lag’s hours convert on the predecessor’s calendar (that is what P6 states), but the lag is then counted in whichever calendar the project’s lag-calendar option names — predecessor’s, successor’s, project default, or 24-hour. Two different calendars are involved in one lag, and conflating them is a common importer defect.
Calendar parsing
P6’s calendar blob is a proprietary format. Closures, holidays, weekly patterns, and hours-per-day are all packed into one string. Real files occasionally contain blobs that do not parse cleanly — corrupted by manual edits, partial exports, or version differences. A good importer quarantines the unparseable calendar and the activities using it, rather than silently assigning a default.
After import, verify that each calendar’s working days match what you expect. Check a monsoon closure, a Diwali holiday, a six-day pattern. Calendar errors propagate to every activity using that calendar, so one wrong exception date can move hundreds of finishes.
Constraint semantics
The nine constraint types are well-defined, but their interaction with the data date and with mandatory logic can surprise. A Must-Start-On constraint overrides logic — an activity constrained to start on 15 March will be scheduled there regardless of its predecessors. After import, check that your mandatory constraints (MSO, MFO) are still behaving as overrides, not as suggestions.
External dates — external_early_start and external_late_finish, which appear in partial exports where cross-project logic was severed — should import as explicit boundary constraints with their provenance visible, not as invisible floors or ceilings on the dates.
Content the format ignores
WBS-level weighted milestones have no evidenced table in the XER format. If your programme uses weighted milestones at the WBS level for progress measurement, those will not travel in the file.
WBS-summary activities (TT_WBS) are group rollups, not real activities; they should be dropped on import, since any receiving system computes rollups live.
The parallel-run approach
A migration does not require a migration day. The pattern that works:
Step 1 — Import. Take the current programme’s XER and import it. Before anything is written, review the pre-write report: activity count, link count, calendar count, quarantined rows (with reasons), content the importer cannot carry (with counts), and the scheduling options the file states. Verify the computed dates against P6. If the critical path and the float agree, the engine’s semantics match; if they do not, find out why before proceeding.
Step 2 — Run in parallel. Keep P6 as the system of record on the live project. Each week (or each statusing cycle), export a fresh XER from P6 and re-import it. The re-import should show you a preview before writing anything: how many activities matched, how many are new, how many are missing, how many carry progress updates, and where the data date is moving to. If your team has made edits in the new system — fixed a duration, added a link — the re-import should surface each collision: the file says one thing, your edit says another, and you choose.
Step 3 — Commit or walk away. After several cycles, the programme, its history, and its configuration already live in both systems. If you are satisfied, you stop exporting from P6. There is no migration day because the migration happened incrementally, one re-import at a time. If you are not satisfied, you stop re-importing and nothing was lost — P6 never knew about the parallel run.
Re-import and per-class update rules
Re-import is where migration fidelity is tested hardest, because you are merging a file into a project that already has edits.
Matching. Activities match by their activity code (the planner-facing ID, not the internal database key — import preserves the source ID). Calendars, WBS nodes, and resources match by source ID, then by name. Unmatched source rows are inserts. Unmatched existing records are proposed for retirement — proposed, never silently deleted.
Per-class choices. For each class of data — activities, links, constraints, calendars, WBS structure, resources and assignments, progress — you choose one of four rules: update existing records from the file, keep existing records and ignore the file, insert only new records, or skip the class entirely. These choices should be previewed with counts before you confirm.
Progress as measurements. The file’s actual dates, remaining durations, suspend/resume dates, and expected finishes should land as statusing facts with import provenance — not overwrite manually entered progress without notice.
Steps ride with their activity. Activity steps carry no stable ID that a file and a project can match on. A new activity takes the file’s steps; a matched activity keeps the steps it already has. Matching steps by name would be guessing.
Silence is not a value. A file that states nothing about a field — no duration type, no percent-complete type — says nothing. It does not say “use the default.” A re-import that compares silence against a stored value will generate false collisions on every field the file omits.
What to verify after import
Run these checks against every import, whether it is the first or the fifteenth re-import.
Activity count. Compare the count in the import report against the count in P6. Account for WBS-summary activities (dropped) and any quarantined rows.
Date agreement. Compare the early start and early finish of a sample of activities — start with the critical path — against P6’s computed dates. Disagreements point to calendar differences, scheduling option differences, or constraint handling differences. A one-day disagreement on a hundred activities is usually a rounding issue. A multi-day disagreement on a critical activity is usually a semantic difference worth understanding.
Critical path. Verify that the same activities are critical. If the critical set differs, check the lag calendar option, the progressed-logic mode, and the total-float basis — these three options account for most critical-path disagreements between systems.
Calendar assignment. Verify that each activity is using the calendar you expect. A calendar mapping error — “P6 6-Day Standard” mapped to the wrong library calendar — moves every activity using it.
Constraint count. Check that your constraint count matches. MSO and MFO constraints are the highest-risk: they override logic, so a missing mandatory constraint changes the schedule silently.
Float. Compare total float on a sample of near-critical activities. Float disagreements usually trace back to the same three scheduling options.
Scheduling options. Verify that the imported project’s scheduling options match the source file. The lag calendar, the progressed-logic mode, and the SS-lag basis are the three that move dates. The expected-finish flag, the open-ends-critical flag, and the total-float basis affect float and the critical set.
A programme that passes these checks computes the same schedule you had in P6, under the same rules. At that point, you are not trusting a new system — you are verifying that two systems agree on the arithmetic, which is a conversation any planner knows how to have.