Stop Using bench update Blindly — Here's How to Update One Frappe App Safely

Update frappe Specific App Only

How to Update Only Frappe or a Specific App in Your Bench (Without Breaking Anything)

Stop risking your entire bench. Learn the surgical way to update a single Frappe app while keeping everything else untouched.

⏱️ Time to Complete: 10–15 minutes

🎯 What You'll Learn

  • ✅ How to selectively update only one app (Frappe, ERPNext, or your custom app) using the --apps flag
  • ✅ The manual step-by-step approach when you want full control
  • ✅ How to fix the 4 most common blockers — permission errors, 503 pages, shallow clone warnings & merge conflicts
  • ✅ A quick-reference cheatsheet you can bookmark for daily use
  • ✅ Best practices for safe, zero-downtime updates on production

📋 Prerequisites

Before you dive in, make sure you have:

  • A working Frappe Bench installation (version 15 or 16)
  • Basic comfort with the terminal and Git
  • Your bench directory path handy — typically ~/frappe-bench or a custom path like ~/f16

[!NOTE] As of June 2026, Frappe v16 is the latest stable release (shipped January 2026). v15 remains supported through end-of-2027. The commands in this guide work on both versions — just swap the branch name where needed (e.g., version-15version-16).


🚨 The Problem with bench update

Let's be honest — running a bare bench update feels like handing the keys to your server and hoping for the best.

Here's what happens by default:

bench update

This single command updates every app in your bench — Frappe, ERPNext, HRMS, and yes, your custom app too. If your custom app has uncommitted changes, is pinned to a specific branch, or has local patches — you're in for a rough day.

The good news? You don't have to update everything. Bench gives you a scalpel instead of a sledgehammer. 🔪


✅ The Right Way: Update Only One App

The Frappe Bench CLI supports an --apps flag that targets a specific app:

cd ~/frappe-bench
bench update --apps frappe

That's it. 🎉

Replace frappe with the name of any installed app:

# Update only ERPNext
bench update --apps erpnext

# Update only your custom app
bench update --apps my_custom_app

🔍 What happens under the hood?

When you run bench update --apps frappe, Bench will:

  1. 🗄️ Back up your site automatically (stored in sites/{site-name}/private/backups/)
  2. ⬇️ Pull the latest code for only the specified app via git pull
  3. 🔄 Run database migrations (bench migrate) to apply schema changes
  4. 🏗️ Rebuild front-end assets (JS/CSS bundles)

Your other apps? Completely untouched. No surprise merge conflicts in your custom code. No broken patches. Peace of mind. 🧘

[!TIP] You can combine the --apps flag with other options for even more control:

bench update --apps frappe --no-backup    # Skip auto-backup (not recommended for prod)
bench update --apps frappe --reset        # Hard-reset to remote branch (discards local changes!)
bench update --apps frappe --pull         # Only pull code, skip migrations & build

🔧 Step-by-Step: Manual Update (Maximum Control)

Sometimes you want to drive stick, not automatic. Here's the fully manual approach that gives you control over every single step.

Step 1 — 🗄️ Back Up First (Always, Always, Always)

bench --site your-site.local backup --with-files --compress

This creates a compressed backup of your database and uploaded files. Even though bench update creates its own backup, having a manual one gives you a safety net you fully control.

[!IMPORTANT] Backups are stored in ~/frappe-bench/sites/your-site.local/private/backups/. For production sites, also consider copying backups to an off-server location (S3, Google Cloud Storage, etc.).

Step 2 — ⬇️ Pull Latest Code for the Target App

cd ~/frappe-bench/apps/frappe
git fetch upstream
git pull upstream version-16   # Use version-15 if you're on v15

[!NOTE] The default remote is usually upstream for official Frappe apps. Run git remote -v to verify your remote names.

Step 3 — 📦 Install Updated Dependencies

cd ~/frappe-bench
bench setup requirements --apps frappe

This ensures any new Python or Node.js dependencies required by the updated app are installed.

Step 4 — 🔄 Run Database Migrations

bench --site your-site.local migrate

This applies any new patches, schema changes, or data migrations that came with the update.

Step 5 — 🏗️ Rebuild Assets

bench build --app frappe

This recompiles the JavaScript and CSS bundles for that specific app only — much faster than a full bench build.

Step 6 — 🔁 Restart Services

bench restart

If you're using Supervisor or systemd in production, this ensures your workers pick up the new code.


🚧 Common Blockers & How to Fix Them

Even targeted updates can hit snags. Here are the four most common blockers and exactly how to resolve each one.

❌ Blocker 1: Permission Denied During pip Upgrade

Error you'll see:

error: failed to remove directory `.../site-packages/pip/_vendor/urllib3/util/__pycache__`: 
Permission denied (os error 13)

🤔 Why it happens: The virtual environment files (~/frappe-bench/env/) are owned by a different user — typically root — so your current user can't modify them. This is common when the bench was initially set up with sudo.

🛠️ Fix:

# Take ownership of the virtual environment
sudo chown -R $USER:$USER ~/frappe-bench/env

# Re-install dependencies
bench setup requirements

# Finish the update
bench --site your-site.local migrate
bench build --app frappe

[!TIP] To prevent this from happening again, avoid using sudo when running bench commands. If your bench was set up by root, consider transferring full ownership:

sudo chown -R $USER:$USER ~/frappe-bench

❌ Blocker 2: Site Stuck on "System is Updating" (503 Error)

What you see in the browser:

Updating
The system is being updated. Please refresh again after a few moments.
Status: 503

🤔 Why it happens: When bench update runs, it puts your site into maintenance mode — a locked state that blocks user access during migrations. If the update is interrupted midway (by an error, a network drop, or an SSH timeout), the site stays locked. Bench forgot to unlock the door. 🚪🔒

🛠️ Fix:

# Disable maintenance mode
bench --site your-site.local set-config maintenance_mode 0

# Resume the background job scheduler
bench --site your-site.local set-config pause_scheduler 0

# Restart all services
bench restart

Refresh your browser — the 503 should be gone and your site should be back to normal. ✅

[!WARNING] If the update was interrupted during a migration, your database might be in a partially migrated state. After clearing maintenance mode, run bench --site your-site.local migrate to complete any pending patches.


❌ Blocker 3: shallow_clone Warning

Warning you'll see:

WARN: shallow_clone is set in your bench config.
However without passing the --reset flag, your repositories will be unshallowed.

🤔 Why it happens: Your bench was initially set up with shallow_clone = true in the config. Shallow cloning downloads only the latest commit history (saving disk space and time during setup). When you update without the --reset flag, bench unshallows the repository — downloading the full git history — which is slower and triggers this warning.

🛠️ Fix (suppress the warning permanently):

bench config set-common-config -c shallow_clone false

This tells bench to treat all repos as full clones going forward. The next update will proceed without the warning.

[!NOTE] If disk space is a concern (e.g., on small VPS instances), you can keep shallow_clone = true and simply pass the --reset flag during updates instead:

bench update --apps frappe --reset

Just remember that --reset discards any local changes in the app's repo.


❌ Blocker 4: Merge Conflicts on Update

Error you'll see:

error: Your local changes to the following files would be overwritten by merge

🤔 Why it happens: Someone made direct edits to the app's source files — modifying core Frappe or ERPNext code instead of using Frappe's built-in customization tools (Custom Fields, Client Scripts, Server Scripts, etc.).

🛠️ Option A — Discard local changes (if you don't need them):

cd ~/frappe-bench/apps/frappe
git reset --hard upstream/version-16

[!CAUTION] git reset --hard is destructive and irreversible. Only use this if you're 100% sure you don't need the local changes. Consider backing up the files first.

🛠️ Option B — Stash and reapply (if you want to keep changes):

cd ~/frappe-bench/apps/frappe
git stash                         # Save your changes aside
git pull upstream version-16      # Pull the latest code
git stash pop                     # Reapply your changes on top

If there are conflicts after git stash pop, Git will mark the conflicting files. Open them, resolve the conflicts manually, then:

git add .
git commit -m "fix: resolve merge conflicts after update"

🔎 How to Check Your Site's Current Status

Before and after any update, always verify your site's configuration to ensure everything is in order:

# Quick check using bench
bench --site your-site.local show-config

Or inspect the raw config file:

cat ~/frappe-bench/sites/your-site.local/site_config.json

Key values to look for:

Config KeyExpected ValueWhat It Means
maintenance_mode0Site is live and accessible
pause_scheduler0Background jobs are running

If either is set to 1, your site is still in maintenance mode — use the fix from Blocker 2 above. 👆


🎁 Bonus: Update the Bench CLI Itself

Here's something that trips up a lot of people: the Bench CLI tool and the Frappe framework app are two completely different things.

  • Frappe = the web framework (lives in apps/frappe/)
  • Bench = the command-line tool that manages Frappe installations (installed via pip)

To update the Bench CLI:

pip install --upgrade frappe-bench

Bench will also nudge you when a newer version is available at the end of an update run:

INFO: A newer version of bench is available: 5.29.0 → 5.29.1

[!TIP] Run bench version to check your current Bench CLI version at any time.


📋 Quick Reference Cheatsheet

Bookmark this table — you'll thank yourself later. 🔖

TaskCommand
🔄 Update only Frappebench update --apps frappe
🔄 Update only ERPNextbench update --apps erpnext
🔄 Update any specific appbench update --apps app_name
🗄️ Backup before updatebench --site site.local backup --with-files --compress
🔓 Fix 503 / maintenance modebench --site site.local set-config maintenance_mode 0
▶️ Resume schedulerbench --site site.local set-config pause_scheduler 0
🔑 Fix permission errorssudo chown -R $USER:$USER ~/frappe-bench/env
📦 Re-install dependenciesbench setup requirements
🔄 Run migrations manuallybench --site site.local migrate
🏗️ Rebuild assets for one appbench build --app frappe
🔎 Check site configbench --site site.local show-config
⬆️ Update Bench CLIpip install --upgrade frappe-bench
🔁 Restart servicesbench restart
📌 Check Bench versionbench version

💡 Final Tips for a Stress-Free Update

  1. 🗄️ Always backup before updating — even though bench does it automatically. A manual backup gives you a second safety net. Store critical backups off-server.

  2. 🧪 Test on staging first — never update production without testing on a staging or development environment first. Use bench new-site to spin up a test site quickly.

  3. 🚫 Don't edit core app source files directly — use Custom Fields, Server Scripts, Client Scripts, and Custom Apps instead. These survive updates cleanly.

  4. 🎯 One app at a time is always safer than updating everything at once. If something breaks, you know exactly where to look.

  5. 📖 Read the release notes — before updating, check the Frappe release notes and ERPNext release notes for breaking changes and deprecations.

  6. 🔔 Monitor after updating — keep an eye on your Error Log (/app/error-log) and background job status (/app/background_jobs) for the first few hours after an update.


Happy updating! 🚀 If this guide saved you from a broken bench, share it with your team — they'll thank you on the next update day.

Related posts