4. Complete Migration Checklist

PHASE 0 — Assessment & Planning (Days 1–3)

Before creating any environment or writing any code.

Read Frappe v14, v15, v16 GitHub changelogs and CHANGELOG.md for all three versions

Run FRAPPE_DEPRECATION_WARNINGS=1 on v14 production; capture all warnings

Audit all custom apps: hooks.py, Python API calls, JS API calls, Vue components

Identify all scheduler_events and validate cron expressions against v16 syntax

Identify all third-party pip packages; check Python 3.11 compatibility

Confirm Redis version (7+ needed for v16), MariaDB version (10.6+ min), OS (Ubuntu 24.04+)

Define go/no-go criteria for V15 UAT and V16 UAT separately

Write rollback plan for each hop (V14 rollback from V15 attempt; V15 rollback from V16 attempt)

Provision two staging servers (one for V15, one for V16)

Take V14 production backup; verify backup integrity via test restore

PHASE 1 — V15 Staging Bench Setup (Days 3–6)

ENVIRONMENT 2: Validate V14 → V15 hop.

Install Python 3.10+ via pyenv on V15 staging server

Install Node 18+ via nvm on V15 staging server

Install Redis 6+ on V15 staging server

Install MariaDB 10.11 on V15 staging server

Install latest bench CLI: pip install frappe-bench

bench init frappe-bench-v15 --frappe-branch version-15

bench get-app for all apps on their version-15 branches

bench get-app for all custom apps on v15-compat branches

Create site and restore V14 production DB dump

Convert DB to utf8mb4: ALTER DATABASE ... CHARACTER SET utf8mb4 ...

bench --site <site> migrate — monitor and log all output

Resolve all migrate errors; re-run until fully clean

bench build --production — resolve all asset build errors

bench setup supervisor --yes && sudo supervisorctl update

Smoke test: login, create/submit documents, trigger background job, check scheduler

PHASE 2 — V15 Custom App Remediation (Days 5–9)

Fix all custom apps for V15 compatibility.

Create v15-compat branch in every custom app repository

Rename jinja_filters hook to jinja in all hooks.py files

Replace on_login / on_logout hooks with on_session_creation / on_session_update

Fix all frappe.db.sql() calls missing explicit values tuples

Fix frappe.db.set_value() calls relying on implicit auto-commit

Remove all frappe.utils.make_esc() usages

Update website_route_rules entries with required v15 fields

Update app_include_js / app_include_css paths for v15 asset path structure

Run pytest suite on V15 staging for each custom app

Fix all failing tests before proceeding

PHASE 3 — V15 Staging UAT (Days 9–11)

User acceptance testing on V15. Gate before V16 work begins.

Conduct full functional testing across all modules on V15 staging

Test all custom print formats and PDF generation

Test all custom reports and dashboards

Test all email notifications and webhooks

Test all third-party integrations

Conduct UAT with key users and collect written sign-offs

Take clean V15 DB backup after successful UAT: tagged v15-clean

Verify V15 backup can be restored cleanly (test restore to temp DB)

Obtain management go/no-go approval to proceed to V16 phase

PHASE 4 — V16 Staging Bench Setup (Days 11–13)

ENVIRONMENT 3: Validate V15 → V16 hop.

Provision second staging server (or repurpose V15 staging after V15 UAT)

Install Python 3.11+ via pyenv on V16 staging server

Install Node 18+ via nvm on V16 staging server

Install Redis 7 from official Redis apt repository

Install MariaDB 10.11 on V16 staging server

bench init frappe-bench-v16 --frappe-branch version-16

bench get-app for all apps on their version-16 branches

bench get-app for all custom apps on v16-compat branches

Create site and restore the V15 clean DB backup (NOT the original V14 backup)

bench --site <site> migrate (v16 patches only — much fewer than a direct v14→v16 jump)

Resolve all migrate errors; re-run until clean

bench build --production (expect more errors here due to Vue 3 / Vite changes)

bench setup supervisor --yes && sudo supervisorctl update

Full smoke test across all modules

PHASE 5 — V16 Custom App Remediation (Days 12–15)

Fix all custom apps for V16 compatibility.

Create v16-compat branch from v15-compat (not from main) for each custom app

Migrate all Vue 2 components to Vue 3 Composition API

Convert all frappe.call() from callback style to Promise .then() chains

Add vite.config.js to each custom app; remove webpack.config.js

Update hooks.py: app_include paths for Vite dist output, cron strings, doc_events priority

Fix frappe.db.exists() usages relying on return value as doc name

Fix frappe.get_all() calls with or_filters as positional argument

Update frappe.whitelist() decorators to include methods=['GET'/'POST']

Replace frappe.session.data.user_type with frappe.get_user().doc.user_type

Update all frappe.utils.dateutils imports to frappe.utils.date_utils

Resolve all Python 3.11 package conflicts in requirements.txt

Run pytest suite on V16 staging for each custom app

PHASE 6 — V16 Staging UAT (Days 15–17)

Final user acceptance testing before production cutover.

Full functional testing: all modules, all workflows

Test all background jobs end-to-end (enqueue, process, result)

Test all scheduler jobs by triggering via bench execute

Test all custom print formats, PDF generation

Test all email notification templates

Test all REST API / webhook integrations

Test file upload and attachment handling

Performance test: simulate peak concurrent users

Conduct UAT with key users; obtain written sign-offs

Run second V16 staging migration from scratch (fresh V15 backup → V16 migrate) as final rehearsal

Finalise production cutover runbook with step-by-step commands and timings

Obtain final management go/no-go for production cutover

PHASE 7 — Production Cutover (Day 18)

Two-hop production migration: V14 → V15 bench → V16 bench.

Announce maintenance window; enable read-only notice for users

Take FRESH full backup of V14 production: mysqldump + bench/sites/ snapshot

Verify fresh backup by checking row counts against known totals

bench set-maintenance-mode on for all production sites

Stop all workers: sudo supervisorctl stop all

--- HOP 1: V14 Production DB → V15 Production Bench ---

On V15 production bench server: restore fresh V14 backup to MariaDB

Convert DB to utf8mb4 (if not already done on production DB)

bench --site <site> migrate (V15 patches) — log all output with timestamps

bench build --production on V15 bench

Quick smoke test on V15: login, open key DocType, verify data integrity

Take V15 bench backup: mysqldump tagged v15-prod-cutover

--- HOP 2: V15 Production DB → V16 Production Bench ---

On V16 production bench server: restore v15-prod-cutover backup to MariaDB

bench --site <site> migrate (V16 patches) — log all output with timestamps

bench build --production on V16 bench

bench setup supervisor --yes && sudo supervisorctl reread && sudo supervisorctl update

bench setup nginx --yes && sudo nginx -t && sudo systemctl reload nginx

bench set-maintenance-mode off

Full smoke test: login, create/submit documents, trigger background job, generate PDF, send email

Monitor bench logs in real time for 30 minutes post-go-live

Announce go-live to users; begin hypercare period

PHASE 8 — Post-Live Stabilisation (Days 19–20+)

Hypercare, issue resolution, performance tuning.

Daily log review for first 5 business days: bench logs --all

Monitor background job queue depth in Frappe desk daily

Address all P1 issues within 24 hours; P2 within 72 hours

Run bench doctor daily for first 3 days post go-live

Confirm all scheduled jobs firing on correct schedule

Tune worker concurrency based on observed queue lengths

Schedule user re-training sessions for changed workflows (Vue 3 desk UI differences)

Update all internal developer documentation to Frappe v16 APIs

Decommission V14 and V15 staging benches after 30-day post-go-live stability period

Conduct migration retrospective; update this document with lessons learned