Technical Tutorials 14 min read

Updating ERPNext v15: What Every Command Does and What Can Go Wrong

ERPNext updates come in three kinds, and the risk is not the same for each. Category 1: minor patches (v15.22 → v15.26) — low risk, about 15 minutes. Category 2: major version upgrade (v14 → v15) — high risk, needs a staging environment, plan for 4-8 hours. Category 3: framework update (changes in the Frappe core) — medium risk, same process as a minor patch, but read the release notes first. The expensive mistake is treating a major upgrade like a minor patch. Here is how to run each one properly.

The Golden Rule: The Backup You Take Before Updating Is Your Insurance Policy

Updating is where most self-hosted ERPNext installs break. On Managely, updates are tested on a copy of your data first, and roll back automatically if anything fails.

Never run bench update again
Non-Negotiable: Do This Before Every Update

Every update must start with a verified backup. Not a backup you assume exists — a backup you just took and confirmed the file exists on disk. One corrupted update without a backup = permanent data loss. There is no undo button in a database.

bash
# Take a complete backup before EVERY update (run as frappe user)
cd ~/frappe-bench
bench --site mycompany.com backup --with-files

# Confirm the backup file actually exists and has content
ls -lh sites/mycompany.com/private/backups/
# You should see a .sql.gz file created in the last 2 minutes
# It should be more than 1 KB — a 0 byte file means the backup failed

# Get the exact filename for use in rollback if needed
ls -t sites/mycompany.com/private/backups/*.sql.gz | head -1

Copy the backup to an external location BEFORE starting the update:

bash
# Copy to another server via SCP
scp sites/mycompany.com/private/backups/*.sql.gz user@backup-server:/backups/

# Or upload to S3 (if you have AWS CLI configured)
aws s3 cp sites/mycompany.com/private/backups/*.sql.gz s3://your-backup-bucket/erpnext/

Scenario A: Minor Patch Update (v15.x → v15.y) — Low Risk, 15 Minutes

Minor patches fix bugs and security issues inside the same major version. They rarely break anything that already works. This is the update you run most often, ideally every week or two.

What 'bench update' actually does: (1) git pulls the latest commits for every installed app, (2) updates Python dependencies if requirements.txt changed, (3) runs the database migration scripts if the schema changed, (4) rebuilds the JavaScript and CSS assets.

bash
# Step 1: Take backup (already covered above)

# Step 2: Check what version you are currently on
bench version
# Note this down — you will need it for rollback if something fails

# Step 3: Run the update
bench update --pull

# If you want to run migration separately (safer for large databases):
bench update --pull --skip-migrate
bench --site mycompany.com migrate  # Run migration while you can monitor it

# Step 4: Restart all services to load new code
bench restart

# Step 5: Verify the update succeeded
bench version  # Should show the new version numbers
bench --site mycompany.com doctor  # Checks for any inconsistencies
How to Know the Update Worked

After the restart: log in, open a Sales Invoice and a Purchase Order, and check that the dashboard loads. If anything looks broken or throws an error, go straight to the rollback steps.

Scenario B: Major Version Upgrade (v14 → v15) — High Risk, Use a Staging Environment

Do Not Do This on Production Without Testing on a Clone First

A v14 to v15 upgrade rewrites database table structures, drops deprecated APIs that your custom code may still call, and can break custom print formats and custom fields. Testing on a staging environment with a copy of your real data is not optional. It is the only way to find out what breaks before production finds out for you.

Step 1: Build a staging environment. A separate server, or any server you can afford to break, running a copy of your production database.

bash
# ON YOUR STAGING SERVER (not production!)
# Repeat the full installation from the installation guide first
# Then restore your production backup onto the staging site:

bench new-site staging.mycompany.com \
  --mariadb-root-password DB_PASSWORD \
  --admin-password ADMIN_PASSWORD

# Restore the production database backup onto staging
bench --site staging.mycompany.com restore \
  /path/to/your-production-backup.sql.gz

Step 2: Move staging to v15 and run the upgrade there:

bash
# Switch all apps to the v15 branch
bench switch-to-branch version-15 frappe erpnext hrms

# Update and run migrations
bench update --pull

# If errors appear during migration, they will appear here on staging
# This is exactly why you test here first

Step 3: Test all of this on staging before you touch production: (1) Log in and confirm the dashboard loads with no JavaScript errors — open the browser console (F12) and look for red lines. (2) Open a Sales Invoice created before the upgrade and check that every field is present and correct. (3) Create a new test Sales Invoice and submit it, and confirm it posts correctly. (4) Run the Trial Balance report for last month and confirm the figures match what you had before. (5) Open a custom print format, if you use any, and check it still renders. (6) Submit a test e-invoice (ETA or ZATCA) if that applies to you. (7) Test the POS if your business sells through it.

Step 4: If staging passes every test, apply the same sequence to production inside a maintenance window, at your quietest hour:

bash
# ON PRODUCTION SERVER
# Schedule a maintenance window (e.g., 2 AM Friday)

# 1. Take final backup just before the upgrade
bench --site mycompany.com backup --with-files

# 2. Put the site in maintenance mode so users cannot access during upgrade
bench --site mycompany.com set-maintenance-mode on

# 3. Switch to v15 branches
bench switch-to-branch version-15 frappe erpnext hrms

# 4. Pull code and run migrations
bench update --pull

# 5. Rebuild assets for the new version
bench build --production

# 6. Restart services
bench restart

# 7. Disable maintenance mode
bench --site mycompany.com set-maintenance-mode off

# 8. Verify everything is working
bench version
bench --site mycompany.com doctor

Scenario C: Rollback After a Failed Update — How to Undo in an Emergency

If the update failed and the site is down, this is how you get back to the last working state. Speed matters here: every minute of downtime costs the business something. Bookmark this section before you need it.

bash
# Step 1: Stop all services immediately
sudo supervisorctl stop all

# Step 2: Switch all apps back to the previous version branch
# If you were on v15 and upgrading to v16:
bench switch-to-branch version-15 frappe erpnext hrms

# If you were on v14 and upgrading to v15:
bench switch-to-branch version-14 frappe erpnext hrms

# Step 3: Restore the database from the backup you took before updating
# Replace the backup filename with the actual file you saw in 'ls' earlier
bench --site mycompany.com restore \
  sites/mycompany.com/private/backups/20260405_020000-mycompany_com-database.sql.gz

# Step 4: Rebuild assets for the old version
bench build

# Step 5: Start services
sudo supervisorctl start all

# Step 6: Test the site is working
bench --site mycompany.com doctor
Data Loss Warning on Rollback

Any transactions created AFTER the backup was taken will be lost during rollback. This is unavoidable. It is why the backup must be taken immediately before the update — not the night before. Every hour between backup and update = potential data loss during rollback.

If you are reading the rollback section, something already went wrong. Managely tests every update on a copy of your data before it touches production.

See how our updates work

How to Check What Changed Before Updating (Read Release Notes Like a DevOps Engineer)

Before any update, spend 5 minutes on the release notes. They tell you whether this release touches something you depend on.

bash
# See what commits are incoming before pulling them
git -C apps/erpnext log --oneline HEAD..origin/version-15 | head -20
git -C apps/frappe log --oneline HEAD..origin/version-15 | head -20

# Check if any migration files exist (schema changes = more risk)
ls apps/erpnext/erpnext/patches/
# New patch files since your last update = database will be modified

Why Managed SaaS Handles This Better

Everything above is real operational work, and it has to be done correctly every time. On Managely Cloud, every ERPNext update is tested in a sandbox against a snapshot of your actual data before it is applied. When it is safe, it goes out during low-traffic hours and you get a notification that your system is updated. Managely is a platform as well as a product: background workers, multiple servers, Git-to-live deploys and your own isolated database, but no terminal to open and no command that can damage live records. Your part of upgrade night is reading the notification.

Tested Updates

Managely tests every update against real data patterns before deployment. Major version upgrades are staged, verified and applied with no action required from you. ETA and ZATCA compliance updates are handled centrally and deployed for you, so you are not the one patching them the week they are due.

Already self-hosting? Send us your backup - we'll restore it on Managely for free. If it isn't better, take your backup and go.

Migrate my ERPNext free

Let someone else own the risky upgrade night.

Marketplace apps, one dataset, your plan.

Leave a comment

Comments