Upgrading ERPNext on Docker with frappe_docker

Upgrading containerized ERPNext means building new images, not patching running containers, then migrating every site. This page covers the supported path, the upgrade sequence and what drives effort.

On this page

How to upgrade ERPNext on Docker with frappe_docker without patching live containers

If your containerized ERPNext site has to move to a newer version, the upgrade is not something you apply to the running containers. Containers in frappe_docker are immutable, so the work is to build new images that carry the target ERPNext and companion app versions, point your Compose or deployment configuration at those images, and then run a database migration against your sites. The new image is the upgrade, and the migration is the step that changes your data. Plan the two together, because a new image running against an unmigrated database is a failure you have to recover from. The reason this matters now is the calendar: according to Frappe's supported versions page, ERPNext and Frappe Framework version 14 reached end of life on January 31, 2026. The supported paths are version 15, planned for support until the end of 2027, or version 16, planned until the end of 2029. Confirm the current support dates on that page before you choose a target, since they can change.

Start by listing every app baked into your custom image, not only ERPNext. Each app needs a branch or tag that matches the target version, and apps that split out in newer releases must be installed explicitly. Check the target release notes in the frappe/erpnext releases page and the matching frappe_docker build inputs before you rebuild. Your own custom apps also need a compatibility check against the target Frappe version, because a build can succeed while the app still breaks at runtime. Record the exact versions you built so the same image can be reproduced if you need to roll back. An image that was rebuilt from floating branches is hard to audit later.

Run the migration as a deliberate step with a known outcome. The frappe_docker documentation says that after you update a custom image or deploy new app versions, you must run bench migrate. The migrator Compose override runs bench --site all migrate on container start, but other services do not wait for it, so your deployment must check the migrator's exit status before it routes traffic to the new containers. Take a verified database backup first, test the whole sequence on a copy of production, and confirm that rollback means redeploying the previous image with a restored backup, since a migrated schema generally cannot be reversed by swapping images back. Ask your team to confirm how your backup tooling and retention interact with the migration window.

What changes between versions and what each change asks of you

This table compares the version facts that affect a containerized ERPNext upgrade, with the impact of each and the action your team needs to take. Read it before you pick a target version, then confirm each version's release notes before you rebuild images.

ChangeImpact on a frappe_docker deploymentAction needed
ERPNext and Frappe v14 end of lifeVersion 14 reached end of life on January 31, 2026, so sites still on it no longer receive fixes from Frappe.Plan a move to version 15 or 16, and confirm the upgrade path with your team before changing the image tag.
Supported versions 15 and 16Version 15 is planned for support until the end of 2027 and version 16 until the end of 2029, per Frappe's supported versions page.Choose the target line by your support window, then pin the matching app branches in your custom image build.
Frequent minor releasesBoth supported lines publish frequent minor releases, such as v15.123.0 and v16.51.1, so the image you built today will age quickly.Rebuild the image on a schedule, run bench migrate after each rebuild, and test on a staging stack first.
Warranty coverage requires a support planFrappe's policy ties warranty coverage to a listed version and a matching Frappe Cloud support plan, which a self-hosted Docker stack does not get automatically.Ask Frappe or your partner whether a support subscription applies to your version and deployment before you sign off the plan.
Server Scripts disabled by default from version 15Server Scripts no longer run unless the server_script_enabled setting is turned on, so document event logic may silently stop firing after the upgrade.Inventory every Server Script, decide whether to enable the setting, and retest each script on the target version.
App splits in version 15Features moved into companion apps must be present in the image before migrate runs, or the migration can fail or leave gaps in features.Add the companion apps to the custom image and confirm their branches match your ERPNext version before running the migrator.
Release notes for each versionBreaking changes can appear between minor and major releases that this page does not list, and the release notes are the source of truth.Read the release notes for every version you pass through and confirm each change against your custom apps and customizations.

What to prepare before you rebuild the image

Each item below is a document, a backup or a running environment that the team must have in hand before the new image is built. Together they let you test the upgrade on copies of your data, prove you can return to the previous state, and know exactly which code and customizations the new image has to carry.

Full database and file backup

Take a full database dump and a copy of the sites directory, including private and public files, before anything changes. Confirm that the backup restores into a clean MariaDB container and that the site loads afterward. Record the backup timestamp and checksum in the change ticket so the rollback step uses a known artifact, not the most recent file.

Inventory of custom apps and customizations

List every custom Frappe app, every Custom Field, Property Setter, Client Script, Server Script, print format and report in each site. Mark which ones depend on removed or changed APIs in the target version. Server Scripts need particular attention, because from version 15 they are disabled by default and must be enabled with the server_script_enabled setting before they run.

Pinned target app versions

Write down the exact ERPNext, Frappe and companion app branches or tags the new image will build from, and set them explicitly in the image build arguments rather than tracking a moving branch. Check each pinned version against the supported versions list before the build. A rebuild that pulls a different minor release than the one you tested is a common source of unexplained differences.

Staging stack from the same Compose files

Run a staging copy built from the same Compose files, the same image tags and a restored copy of production data. Use the migrator override there first and watch its exit status, since the other services will not wait for it. The staging stack should be separate from production networks and must not send email or call external payment or integration endpoints with live credentials.

Written rollback plan

Document the steps to return to the previous image tag, restore the database and files from the verified backup, and bring the services back up. Name the person who makes the rollback decision and the time limit after which you stop forward migration attempts. Keep the previous image in your registry until the upgrade has run stably for the agreed period.

Choosing the upgrade path for your site count and app set

A single site running the stock frappe_docker images has the simplest upgrade path. You rebuild or pull the image for the target ERPNext version, point the deployment at it, and let the migrator run bench --site all migrate once against the one site. Nothing custom sits between the image and the database, so the main risk is the release notes for the target version rather than dependency conflicts.

  • Migrator target: The migrator runs against the single site in the stack, so confirm the site name matches what the Compose override expects.
  • Pre-install: No extra apps are needed beyond ERPNext itself, but confirm whether you have any apps baked in by default.
  • Image tag: Pin the image to the exact ERPNext release you have tested, not a floating tag.
  • Backup: Take a database backup before the migrator starts, since it changes the schema in place.
  • Exit status: Other services do not wait for the migrator, so check its exit status before you consider the deployment healthy.

Confirm with your own test environment that the site loads, reports render and scheduled jobs run after the migrator completes.

The upgrade sequence: build, migrate, verify, roll back

This sequence moves a containerized ERPNext site to a new version in a controlled order, so every change has a tested staging run, a verified database backup to return to, and an explicit check before production traffic reaches the new code.

  1. Freeze writes and take backups

    Stop user writes to the site by putting it in maintenance mode or pausing access at the proxy, and let background jobs drain. Then take a database backup and a copy of the site's files volume, including private and public files and the site configuration. Record the current image tags and app commits so the previous state can be rebuilt exactly. This is the rollback point: once the backup is verified by restoring it to a scratch database, you can return to the old images and data at any later step without losing transactions made before the freeze.

  2. Rebuild the custom image with target branches

    Rebuild the custom image with the target Frappe and ERPNext branches and the matching branches of every companion and custom app. Pin each app to a specific commit rather than a moving branch name, and record the resulting image digest. Do not patch a running container, because frappe_docker treats containers as immutable: only environment variables and mounted volumes change between runs. Done means the build completes, the image is pushed to your registry, and the app list reported by the new image matches the list you planned.

  3. Deploy the new image to staging

    Deploy the new image to a staging environment that is a recent copy of production, with the same Compose file, environment variables and volumes. Keep staging on the same database engine and version as production, and keep the staging site's mail and integration endpoints disabled or pointed at test systems. Use the frappe_docker migrator override in the staging run, since the migration steps that follow are the ones you are rehearsing. Done means the new containers start on staging and the site is reachable on its internal address.

  4. Run the migration and check its exit status

    The frappe_docker migrator override runs bench --site all migrate when its container starts. Other services do not wait for it, so the backend, workers and scheduler may start while the schema is still changing. Confirm the migrator container exits with status 0 before you treat the upgrade as successful, and read its log for errors. If you prefer explicit control, run bench --site all migrate yourself in a one-off container and check its exit code. A non-zero exit means the site is not ready: stop, keep the rollback point, and investigate before starting further work.

  5. Clear caches and restart services

    After a successful migration, clear the site cache and restart the backend, worker, scheduler and Socket.io services so that every process loads the new code and schema. Cached assets from the old build can otherwise cause mismatched pages or failed API calls even when the database is correct. In CI, make sure the image build does not reuse stale layers for the app source, so the restarted services run the commits you pinned. Done means all services report healthy and the site serves its login page with the new version number.

  6. Run smoke tests on staging

    Run a scripted set of checks against staging before any production change. Cover login, a sample of documents in each module you use, a posted accounting entry and its ledger report, stock movements and valuation reports, print formats, scheduled jobs and any custom server scripts or integrations. Compare key totals against the pre-upgrade production figures for the same period. Done means every check passes, and each failure has a recorded fix or a decision to hold the upgrade. Ask your implementation partner or internal QA owner to sign off on the results.

  7. Promote the verified build to production

    Repeat the freeze, backup, build reference, migration, exit check, cache clear and restart steps on production, using the same image digest and commits that passed staging. Do not rebuild on production day, because a new build can pull newer app commits. Re-run the smoke tests against production, then lift maintenance mode and watch error logs and the background job queue. If a step fails, return to the backup taken at the rollback point, restore the previous image digest and confirm the old version serves traffic before you investigate.

Invalidating cache in CI builds so new app versions are included

A CI build can quietly ship the old application code. Docker builds reuse cached layers whenever the instructions and their inputs look unchanged, so if the step that fetches your ERPNext and companion app source keeps the same reference from one run to the next, the cached layer is reused and the image still contains the previous app code. The fix is to make the app reference an explicit input to every build. Pin each app to a specific version tag or commit SHA in the build arguments or app definition your pipeline passes in, and change that value whenever you want new code. A branch name such as a moving version-16 reference is a common trap, because the text of the instruction never changes even though the code behind it does. Confirm which build arguments your frappe_docker version expects for app sources and whether it accepts commit references, since the exact names differ between releases and are described in the automated builds guide.

When you need to force a rebuild of the app layer without changing the pinned reference, use your CI system's no-cache option for that build, or add a changing value such as the build date or pipeline run ID as a build argument placed before the app fetch step. Either approach works, but a no-cache build for every run is slower and hides the real dependency chain, so most teams prefer the explicit pinned reference and keep no-cache as a recovery tool. Check afterward that the new image actually contains the expected app code, for example by reading the app version from the container, before you deploy it.

Tag every image with an identifier unique to the build, such as the commit SHA of your deployment repository or a release version, and use that same tag for the migrator service and for the backend, worker, scheduler and Socket.io services. If the migrator runs one image and the web services run another, bench migrate can update the database for code that the running services do not yet have, or the reverse. Using one tag across all services in the Compose or deployment file, and failing the deployment when the migrator exits with an error, keeps the code and schema in step.

What makes a containerized upgrade take longer

This table compares each factor that changes the effort of a containerized ERPNext upgrade, with what raises it and what lowers it. Read each row against your own estimate of sites, apps and data, since the factors add up and a single large one can outweigh several small ones. Most of the time is lost in custom code that touches changed doctypes and in the absence of a staging stack to find those problems first.

DriverWhat raises effortWhat lowers effort
Number of sitesMany sites on one bench, each needing its own bench migrate run and its own post-upgrade checksOne or two sites, or sites grouped by identical apps and customizations so one test covers several
Custom apps: number and ageOld custom Frappe apps not maintained against the target version, with hooks or APIs that changedFew custom apps, recently tested, with a known owner and a version pinned in the image build
Customizations touching changed doctypesCustom fields, scripts or print formats on doctypes whose fields or behavior changed in the target releaseCustomizations kept in exported fixtures, with a list of doctypes each one touches reviewed before the build
Database size and migration runtimeLarge transaction tables, many stock or ledger entries and long migrate runs that must fit the maintenance windowArchived old data, a recent backup restored to staging to time the migration, and an agreed window
Server Scripts in useServer Scripts that call changed methods, and the need to confirm they are enabled on the target versionNo Server Scripts, or scripts moved to custom apps with tests
Companion apps that must match branchesApps such as Frappe HR or India Compliance pinned to different branches per site, each rebuilt and retestedA single app list in the image build, with branches matched to the ERPNext target version
Staging stackNo staging stack, so the first run of the new image happens against production dataA staging stack built from the same image and a recent copy of production data, with the migrator exit status checked

Questions buyers ask before upgrading ERPNext on Docker

What drives the cost of upgrading ERPNext on Docker?

The cost follows the amount of work in the written scope, not the container tooling itself. The main drivers are how many versions you jump, how many custom apps and customizations must be retested, how many sites share the bench, how much data needs checking between steps, and how much of the rebuild pipeline already exists. Self-hosting ERPNext is free according to the ERPNext pricing page, so the spend is labor and infrastructure: staging environments, build capacity and the people who test. Ask any provider for a quote that separates one-time upgrade work from recurring support, and that lists which apps and sites are in scope.

Can our in-house team upgrade ERPNext on Docker by itself?

Often yes, if the team already runs Linux, Docker and a MariaDB-backed application, and has someone who can read app changelogs. The upgrade needs a rebuilt image with matching app versions, a migrate step run against a copy of production, cache invalidation in the CI build, and tests of custom code. Teams without those skills, or without a staging environment that mirrors production, usually take longer and carry more risk. Compare the cost of your engineers' time against a partner's fixed-scope proposal before deciding.

What does the upgrade need from our team?

Expect to provide access to the staging and production hosts, a current backup, the list of custom apps and their repositories, and named people who can sign off business processes such as accounting closes and stock counts. You will also need someone who owns the decision on which Frappe and ERPNext versions to target. Confirm these items in the written scope so that testing time is not lost waiting for access or answers.

How long does an ERPNext upgrade on Docker take?

No duration can be stated here without the scope, so treat any single figure with caution. Timing depends on the number of major versions crossed, the size of the database, the number of custom apps, and how many test cycles the business requires. Frappe's supported versions page lists the end-of-life dates for version 14 and the planned support windows for versions 15 and 16, which affects which target you choose and how urgent the work is. Ask for a timeline that lists each stage and the checks at its end.

Do we need a paid support plan after the upgrade?

Frappe's supported versions policy states that customers must be on a listed version and subscribed to a matching Frappe Cloud support plan to receive warranty coverage from Frappe. If you self-host outside Frappe Cloud, that warranty question is separate from your operational need. Consider a retainer for minor releases, which ship frequently for both supported major versions, and for incident response. Frappe Cloud shared site hosting starts at 5 US dollars per month and dedicated servers at 125 US dollars per month, according to the ERPNext pricing page, but those prices cover hosting, not a self-hosted upgrade.

What goes wrong most often during a Docker-based upgrade?

The most common failures are an image built with app versions that do not match the Frappe version, a migrate step that is skipped or fails silently, and stale cached layers in CI that ship old code. Because the migrator service runs bench --site all migrate on start and other services do not wait for it, a deployment can route traffic to a site before its schema is ready. Check the migrator's exit status before cutover, and test custom scripts, which Frappe disables by default from version 15.

Should we get a fixed-scope quote before starting?

Yes. DeployOpen does not publish a price list, and most engagements are fixed-scope, with scope, deliverables and timelines agreed in writing before work starts. Ask for a quote that names the source and target versions, the apps and sites in scope, the environments to be built, the tests to be run, the rollback plan, and what happens after go-live. A written scope makes it possible to compare proposals from partners and your own team on the same basis.

Testing the upgraded site and rolling back safely

Test the upgraded image on a staging copy of production before any traffic reaches it, and decide in advance what result would send you back. Restore a recent production database backup into staging, run the new image against it, and then run bench --site all migrate through the migrator service and check its exit status, since the other services do not wait for it. Then work through the business paths that break most often after an upgrade: login, including any LDAP or Social Login Key setup, because identity settings live in the database and a changed callback URL or provider configuration will fail silently for some users; print formats and reports on real invoices, stock ledgers and financial statements; scheduled jobs, which should be confirmed to run on the workers and scheduler; outbound email; and each integration your sites depend on. Confirm that Server Scripts still behave as expected if you use them, since their enablement is controlled by the server_script_enabled setting and should be checked after the change.

Set rollback criteria before the upgrade window opens. Typical triggers include a failed or partial migrate, a failed login path for a significant user group, incorrect financial output in a report that is used for close, or jobs that stop running. Rolling back a containerized ERPNext site has two parts that must be done together: restore the pre-upgrade database dump taken immediately before the migrate, and redeploy the previous image tag. Restoring only the image leaves the schema in the new state and the old code will not match it. Restoring only the database leaves the new code running against old data. Keep the previous tag, the Compose file and the environment file in version control so that the exact prior state can be redeployed without rebuilding. Confirm with your own runbook how long a restore takes for your database size and whether the restore is tested before go-live.

Record every finding from staging, including the image tag and migration output, so the production sign-off is based on evidence rather than memory. Any rollback should be followed by a review of the failing step before a second attempt, and the staging copy should be refreshed from production before the next try so that data changes made after the first attempt are included. Ask your team to confirm who holds authority to call a rollback, how that decision is communicated to users, and what happens to transactions entered during the failed window, because those records will need reconciling against the restored database.

How DeployOpen scopes, delivers and supports your ERPNext upgrade

DeployOpen approaches an upgrade of containerized ERPNext as a written, fixed-scope piece of work on infrastructure you control. We start from your current frappe_docker setup, your custom apps and your sites, then agree the image build, migration and verification steps before any change reaches production.

How we scope

  • We inventory your running images, app versions, custom apps and sites to define the upgrade path.
  • The written scope lists target ERPNext and Frappe versions, the apps to rebuild and the migrate steps included.
  • We agree which environments, test sites and rollback points the engagement covers before work starts.
  • Ongoing support and minor-release patching can be added as a retainer, priced separately from the upgrade.

How we build

  • We rebuild custom images with pinned app branches so each deployed version is traceable to a commit.
  • We configure CI image builds to invalidate caches correctly, so app changes are not silently skipped.
  • We run bench migrate through the migrator service or a controlled job, then check its exit status before rollout.
  • We test customizations, scripts and integrations against the upgraded sites on a staging copy of your data.

How we hand over

  • You receive the build pipeline, Compose overrides and environment variable files used for the upgrade.
  • We document the image tag per site, the migration sequence and the verification checks run at each step.
  • We record the rollback procedure, including how to restore the database backup taken before migration.
  • Your team walks through a runbook covering future image rebuilds, since containers are replaced rather than patched in place.

How we support

  • Support after handover covers questions on image builds, migrations and failed deployments, under the agreed terms.
  • A retainer can cover upgrades to later minor releases, which both supported major lines publish often.
  • We can rerun migration checks on a test site when you plan the next version step.
  • Confirm with us which support terms, response windows and version coverage apply to your scope before signing.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.