ERP Cutover Planning

Plan and execute ERP go-live cutovers that minimize business disruption. Covers cutover timelines, data migration sequencing, parallel run strategies, rollback criteria, team coordination, and the rehearsal practices that separate smooth transitions from disasters.

ERP cutover planning is the process of orchestrating the transition from an existing operational system (legacy, standalone, or fragmented) to a new enterprise resource planning (ERP) system, ensuring data integrity, business continuity, and minimal disruption during the switch. It matters most at the final phase of an ERP implementation: after configuration, data migration, and testing, when the organization is ready to declare “go-live” and live with the new system.

Defining the Cutover Window

The cutover window is a defined period—typically 24 to 72 hours—during which all business operations are frozen in the old system and migrated to the new ERP. It is the operational heartbeat of the transition. The window begins with a final data synchronization and ends when the new system is live, validated, and the old system is decommissioned.

Define the window using a standard cutover.json file in the project root:

{
  "windowStart": "2024-05-15T06:00:00Z",
  "windowEnd": "2024-05-17T06:00:00Z",
  "phase": "cutover",
  "dependencies": [
    "data-migration-complete",
    "backup-snapshot-2024-05-14",
    "test-run-verified"
  ],
  "owners": [
    "[email protected]",
    "[email protected]"
  ],
  "notifications": {
    "slack": "#erp-go-live",
    "email": "[email protected]"
  }
}

This file is consumed by the deployment pipeline. A change to windowStart triggers a pre-cutover alert via curl to a Slack webhook:

curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"text": "Cutover window starts in 6 hours: " + windowStart}' \
  https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

Failure to update cutover.json leads to a mismatch in the expected go-live date: users begin data entry in the new system before the data is ready, and the migration team is unprepared.

Common Cutover Phases

The cutover process consists of five phases, each with defined inputs, outputs, and validation checks:

1. Pre-Cutover (72 hours before windowStart)

SELECT 
  table_name,
  COUNT(*) AS row_count,
  SUM(CASE WHEN is_active = false THEN 1 ELSE 0 END) AS inactive_count
FROM 
  erp_inventory
WHERE 
  last_updated >= '2024-05-15T00:00:00Z'
GROUP BY 
  table_name
HAVING 
  COUNT(*) > 0
ORDER BY 
  row_count DESC;

2. Cutover (windowStart to windowEnd)

./scripts/migrate-final.sh \
  --source=legacy \
  --target=erp \
  --batch=final \
  --validate \
  --backup=erp-final-20240515 \
  --fail-on=10

This script performs:

3. Go-Live (windowEnd to 24 hours post-windowEnd)

systemctl start erp-api erp-web erp-queue erp-warehouse

4. Post-Cutover (72 hours after windowEnd)

0 */6 * * * /opt/erp/bin/validate-postcutover.sh --since=2024-05-17T06:00:00Z

This script compares key metrics between old and new systems:

WITH new_system AS (
  SELECT 
    DATE(created_at) AS day,
    COUNT(*) AS new_count,
    SUM(amount) AS new_total
  FROM erp_sales
  WHERE created_at >= '2024-05-17T06:00:00Z'
  GROUP BY day
),
legacy_system AS (
  SELECT 
    DATE(entry_date) AS day,
    COUNT(*) AS legacy_count,
    SUM(value) AS legacy_total
  FROM legacy_sales
  WHERE entry_date >= '2024-05-17T06:00:00Z'
  GROUP BY day
)
SELECT 
  ns.day,
  ns.new_count,
  ls.legacy_count,
  (ns.new_count - ls.legacy_count) AS delta
FROM new_system ns
JOIN legacy_system ls ON ns.day = ls.day
WHERE ns.new_count > 0 OR ls.legacy_count > 0
ORDER BY ns.day DESC;

Failure: if delta exceeds 10% of average daily volume, alert via curl to a PagerDuty integration.

5. Decommissioning (1 week after windowEnd)

Cutover Execution: The Real-Time Workflow

At windowStart, a sequence of commands is executed in order:


./scripts/lock-data.sh --schema=erp --duration=4h

# 2. Final data migration
./scripts/migrate-final.sh \
  --source=legacy \
  --target=erp \
  --batch=final \
  --validate \
  --backup=erp-final-20240515 \
  --fail-on=10

# 3. Validate migration
./scripts/validate-migration.sh --batch=final --threshold=99.9

# 4. Start ERP services
systemctl start erp-api erp-web erp-queue erp-warehouse

# 5. Send go-live notification
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"text": "ERP cutover complete. Go-live at 2024-05-15T06:00:00Z"}' \
  https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

Silent Failures in Execution

Data Integrity: The Core of Cutover

The most common failure mode: data inconsistency between old and new systems after cutover.

Validation Checks to Prevent Failures

Define a validation/checks.json file with test cases:

[
  {
    "name": "Sales Orders Match",
    "sql": "SELECT COUNT(*) FROM erp_sales WHERE status = 'confirmed'",
    "expected": 1247,
    "tolerance": 5,
    "description": "All confirmed sales orders must be present in the ERP"
  },
  {
    "name": "Inventory Balance Consistency",
    "sql": "SELECT SUM(quantity) FROM erp_inventory WHERE warehouse = 'main'",
    "expected": 18742,
    "tolerance": 100,
    "description": "Total inventory in main warehouse must be within 100 units of expected"
  },
  {
    "name": "Customer Count Match",
    "sql": "SELECT COUNT(DISTINCT customer_id) FROM erp_sales",
    "expected": 384,
    "tolerance": 10,
    "description": "Number of unique customers in sales data must match"
  }
]

Run validation with:

./scripts/validate-migration.sh --batch=final --threshold=99.9

This script:

Failure output:

Validation failed for batch: final
- [FAIL] Sales Orders Match: expected 1247, got 1231 (diff: -16)
- [PASS] Inventory Balance Consistency: expected 18742, got 18823 (diff: +81)
- [FAIL] Customer Count Match: expected 384, got 373 (diff: -11)
Total: 2/3 checks passed (66.7%)

Cutover Rollback: The Unseen Safety Net

A cutover fails if the ERP system is unstable after go-live. The rollback plan is executed via ./scripts/rollback-cutover.sh:

#!/bin/bash
# rollback-cutover.sh

set -euo pipefail

export BATCH_ID="final-20240515"
export BACKUP_PATH="/backups/erp-final-20240515.dump"

echo "Starting cutover rollback for batch $BATCH_ID"

# 1. Stop ERP services
systemctl stop erp-api erp-web erp-queue erp-warehouse

# 2. Restore from backup
pg_restore -d erp_db -v $BACKUP_PATH

# 3. Re-enable old system
systemctl start legacy-api legacy-web

# 4. Update cutover.json to mark rollback
jq '.status = "rolled-back", .rollback_at = now | .reason = "System instability after go-live"' cutover.json > temp.json && mv temp.json cutover.json

# 5. Notify team
curl -X POST \
  -H "Content-Type: application/json" \
  -d '{"text": "ERP cutover rolled back due to instability"}' \
  https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX

echo "Cutover rollback completed"

Key Failure Points in Rollback

Cutover Communication: The Human Layer

The technical process is only half the story. The cutover team must communicate in real time.

#!/bin/bash
# generate-cutover-report.sh

set -euo pipefail

echo "ERP Cutover Report: $(date)"
echo "===================="

echo "Status: $(jq -r '.status' cutover.json)"
echo "Window: $(jq -r '.windowStart' cutover.json) to $(jq -r '.windowEnd' cutover.json)"
echo "Duration: $(($(date -d "$(jq -r '.windowEnd' cutover.json)" +%s) - $(date -d "$(jq -r '.windowStart' cutover.json)" +%s))) seconds)"

echo "Validation Summary:"
./scripts/validate-migration.sh --batch=final --threshold=99.9 --format=short

echo "Recent Errors:"
grep "ERROR" logs/erp-api.log | tail -5

echo "Next Steps:"
echo "  - Monitor system for 24 hours"
echo "  - Update cutover.json with post-cutover metrics"

This report is posted daily to Slack and archived in /reports/cutover/.

Summary: The Cutover Checklist

The cutover is not a task—it is a sequence of interdependent, time-sensitive, data-driven operations. Its success hinges on precise execution, validation, and communication. A failed cutover is not a system crash; it is a breakdown in the alignment of data, time, people, and process.

This page was rewritten on 17 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.