Frappe/ERPNext 15 Performance Issues Under Concurrent Users

Hi everyone,

We are experiencing performance issues in our Frappe/ERPNext 15 application when multiple users work concurrently. I would like to understand the best way to identify the root cause and optimize the application.

Observed Issues

  1. Login / Initial Page Load
    • Login/initial page load becomes slower when there are concurrent users.
    • With fewer users, the performance is normal.
  2. Overall Application Response
    • Application response becomes slow when multiple users are working simultaneously.
  3. PR / PO / WC List Loading
    • PR/PO/WC list pages take considerable time to load, particularly with increasing data volume.
  4. Version / Audit History
    • Opening Version/Audit information causes noticeable slowness.
  5. Workflow Approval – PR / PO / WC / SCR
    • Moving documents between workflow states takes significant time.
    • We suspect on-save validations/custom logic may be contributing to the delay.
  6. Reports
    • Reports involving large amounts of data become slow, especially when multiple users generate reports simultaneously.

Current Server / Database Information

  • CPU: 2 vCPUs
  • RAM: 7.8 GB
  • Disk: 497 GB total, 425 GB used (86%), 72 GB available
  • Swap: 0
  • Database size: approximately 15.5 GB
  • Frappe/ERPNext bench size: approximately 131 GB
  • Server load at the time checked: 0.40 / 0.38 / 0.42

Some of the larger database tables are:

  • tabVersion – 2.68 GB, ~2.62 million rows
  • tabCommunication – 1.27 GB, ~347k rows
  • tabData Import Log – 654 MB, ~937k rows
  • tabNotification Log – 558 MB, ~208k rows
  • tabItem Plant – 419 MB, ~1.38 million rows
  • __global_search – 363 MB, ~986k rows
  • tabPurchase Receipt – 234 MB, ~39.5k rows
  • tabPurchase Order – 75 MB, ~14.5k rows
  • tabWorkflow Action – 141 MB, ~318k rows

What I would like help with

I don’t want to assume that CPU, RAM, database size, or any particular table is the root cause.

What would be the recommended approach in Frappe/ERPNext 15 to profile and identify the actual bottleneck?

Specifically:

  1. How can we identify slow SQL queries generated by Frappe?
  2. How can we measure the time spent in Frappe/Python hooks such as validate, before_save, on_update, and workflow processing?
  3. How can we check whether Gunicorn/Frappe workers are becoming saturated during concurrent usage?
  4. How can we identify database locks or queries waiting on other transactions?
  5. Are there recommended Frappe tools/settings for profiling slow requests?
  6. With ~2.62 million tabVersion records, are there recommended approaches for optimizing Version/Audit History access?
  7. What should we check for large PR/PO/WC list queries and reports?
  8. Are there recommended production configurations for a server with 2 vCPUs and 8 GB RAM?

Any guidance on a systematic way to identify the root cause before making configuration or database changes would be very helpful.

Thanks!

What about frappe and erpnext version, please increase RAM and vCPUs

erpnext - v15.5.0, frappe -v15.4.0

Splitting App and DB into two server can be considered, or try upgrading to 4vCPU.

And increase the RQ Workers count.

already we have split both server into different IP address. If u wanna suggest how much RQ worker we have to upgrade

Depends on your usage, check System Health Report (from desk) to see if any particular queue is overloaded. By default, you get 1 of each. Maybe you can increase to 2 each and try.

Assuming you’re using MariaDB, refer to Slow Query Log Overview | Server | MariaDB Documentation and enable and monitor slow queries.

Hi @harshithanbhat and welcome to the community

You can use the Profiling and Monitoring (Recorder) tool to measure where the bottlenecks are

Best of luck in identifying the problem

I would start with basic Linux troubleshooting.

Where is all your storage consumed?

If frappe an the DB are under 200Gig, where is the rest of the storage, what other duties/services are running on your server?

sudo du -h —max-depth=1 /

Install htop and run to see system resource allocation.

sudo apt update && sudo apt install htop 
htop

Since you have already separated the app and database servers, I would distinguish slow HTTP requests from delayed background jobs before increasing RQ workers. More RQ workers will not by itself resolve a synchronous workflow request waiting on a database lock, and the low load average is only a snapshot.

The Recorder suggestion above is a good starting point. I would capture one slow PR/PO list request and one workflow transition, then compare SQL time/query count with the Python call profile. At the same timestamps, check database lock waits and app worker utilisation. For Version history, inspect the actual query and its EXPLAIN plan before adding indexes or deleting audit records; table size alone does not identify the cause.

Keep the capture short and preferably reproduce it on staging. Recorder/cProfile adds overhead, so establish the baseline and repeat the same workload after the fix with profiling off. The Frappe profiling documentation explains that distinction. Avoid posting an unredacted capture publicly: it can contain request headers, form data and SQL values.

If the issue is still affecting your team and you want paid implementation help, I can scope the profiling, code/query corrections and before/after validation as one complete project. Roughly how many concurrent users reproduce it, and do you have a budget allocated for the correction? No need to share credentials here.

The memory pressure, availability and lack of cpu cores can cause the issue you are describing. We faced same issue and solved it by increasing server resources (ram and cpu). 2 cores cpu wont take you far with concurrent users. increase it first. do at-least 4vcpus.