Blog article

How "Redis" Makes ERPNext Faster!!

Discover how Redis significantly improves ERPNext performance by reducing database load, accelerating page rendering, processing background jobs efficiently, and enabling real-time communication.

Page details

  • Category: ERPNext
  • Tags: ERPNext,Redis
  • Published on: 04-08-2026

Content

A technical look at caching, background jobs, and realtime updates in Frappe / ERPNext

01

Introduction

If your ERPNext feels slow , forms take a second too long to open, dashboards lag, background emails arrive late , the bottleneck is almost certainly not your server hardware or your MariaDB schema. It is the sheer volume of repeated, low-value database queries that ERPNext makes before it even starts executing your business logic.

Every page render in ERPNext triggers dozens of metadata lookups, permission checks, and session queries against MariaDB. At five users this is invisible. At fifty users, these queries pile up, saturate the connection pool, and make the entire system feel sluggish. The fix is not a bigger server. The fix is Redis , and it is already built into every ERPNext installation.

Redis makes ERPNext faster in three distinct, measurable ways: it eliminates redundant database reads through caching, it moves slow background operations off the web request thread, and it delivers realtime updates to the browser without polling. This article walks through each of these mechanisms in detail and shows exactly why a well-configured Redis layer is the single highest-leverage performance change you can make in an ERPNext deployment.

⚠️ What Happens When Redis is Down or Misconfigured

Redis is not optional. When it goes down or runs out of memory, ERPNext does not just get slower , parts of it stop working:

  • Every page gets slower immediately: Without the cache, each page render falls back to MariaDB for metadata and permissions on every single request. Response times spike 10 to 50 times under normal load.
  • Background jobs stop or get lost: Emails do not send, PDFs do not generate, and scheduled reports do not run. Any jobs queued in memory are lost the next time the server restarts.
  • The UI goes static: Progress bars freeze during imports, desk notifications stop arriving, and document locking breaks , because all of that depends on Redis pub/sub to push updates to the browser.

This is why Frappe ships Redis as a required dependency, not an optional add-on. Getting it right is not a nice-to-have , it directly determines how fast and how reliably your ERPNext runs.

02

Why Redis is So Much Faster Than MariaDB

To understand why Redis makes ERPNext faster, you need to understand what makes Redis fundamentally different from MariaDB at the architecture level , not just "it is in-memory."

When MariaDB receives a query , even a simple primary key lookup , it has to parse the SQL, acquire a query thread, traverse the B-tree index, read data pages from the buffer pool or disk, and return results through the client protocol. Each of those steps takes time. Under concurrent load, multiple queries compete for the same query threads and the same I/O bandwidth. The more users you have, the more those steps overlap and the slower everything gets.

Redis has none of that overhead. It runs on a single-threaded event loop where every command executes atomically in O(1) time directly from RAM. There is no query planner, no index traversal, no disk I/O, no thread contention. A Redis key lookup that would take 15 to 40 milliseconds in MariaDB completes in under 1 millisecond from Redis , every single time, regardless of how many users are active.

This is not a marginal improvement. When ERPNext opens a form and makes 20 to 40 metadata calls, the difference between 15 ms per call (MariaDB) and 0.5 ms per call (Redis) is the difference between a 600ms page load and a 20ms one. Multiply that by every user, every page, every request , and you understand why Redis is the performance backbone of the entire stack.

03

The Three Redis Roles Inside ERPNext

ERPNext does not use Redis in just one place. The Frappe framework provisions three separate Redis instances, each solving a different performance problem. Together they cover caching, job queuing, and realtime communication , three completely different bottlenecks, all addressed by the same infrastructure component.

Instance Port Config Key What It Does
Redis Cache 13000 redis_cache Stores doctype metadata, session tokens, permission results, and expensive query results so MariaDB never has to compute them twice.
Redis Queue 11000 redis_queue Holds background jobs , emails, PDFs, imports, ledger recalculations , so they run asynchronously without blocking user-facing requests.
Redis SocketIO 12311 redis_socketio Acts as the event bus between the Python server and the browser, delivering realtime updates instantly without the browser having to poll.

3.1 Request Flow Across the Stack

The diagram below shows where each Redis instance intercepts work in the request cycle , each one catching a different category of load before it reaches MariaDB or blocks a web worker.

ERPNext Frappe Request Flow with Redis
Figure 1: ERPNext request flow showing where Redis intercepts work before it reaches MariaDB.
04

Caching: Why Your Forms Load Faster

The most immediately noticeable speed improvement Redis delivers is faster page loads , and the reason is caching. When you open any form in ERPNext, Frappe makes dozens of calls to resolve doctype metadata, user permissions, and system settings before rendering a single field. Without Redis, every one of those calls is a fresh MariaDB query. With Redis, they return from RAM in under a millisecond each.

Frappe uses a cache-aside pattern: check Redis first, fall back to MariaDB only on a miss, then write the result back to Redis so the next request never touches the database. After the first user opens a form, every subsequent user gets that form's metadata from cache. The database query happens once. Redis serves it for every request that follows.

Cache Hit versus Cache Miss Decision Flow
Figure 2: Cache hit vs cache miss flow , MariaDB is only queried on a miss, then the result is cached for all future requests.

4.1 What Gets Cached and Why It Matters

The functions that hit Redis most frequently are exactly the ones ERPNext calls most , on every page, for every user, on every request:

  • frappe.get_meta() : field definitions for every doctype on the page
  • frappe.has_permission() : user permission check per record and doctype
  • frappe.get_system_settings() : global configuration values
  • Boot info , the initial desk payload served to the browser on login
  • Dashboard chart queries , expensive aggregations served from cache on repeat loads

Each of these costs 15 to 40 ms in MariaDB. Each costs under 1 ms from Redis. On a single page render with 30 such calls, that is the difference between 1,200 ms of database time and 30 ms from cache. That is where your form-load speed comes from.

4.2 Cache API in Practice

Custom apps in ERPNext can plug into the same cache using Frappe's built-in API. The pattern is identical to what Frappe itself uses internally:

cached = frappe.cache().get_value("branch_wise_sales_summary")

if cached is None:
    cached = compute_expensive_sales_summary()
    frappe.cache().set_value(
        "branch_wise_sales_summary",
        cached,
        expires_in_sec=3600
    )

return cached

Any report or custom script that runs the same expensive query repeatedly is a candidate for this pattern. Once cached, the query runs once per hour instead of once per request , and every user who loads that report gets the result in milliseconds.

05

Background Jobs: Why ERPNext Stays Responsive During Heavy Operations

Have you ever noticed that sending a bulk email campaign or running a large data import does not freeze ERPNext for everyone else? That is Redis Queue at work. Without it, operations like these would execute synchronously inside the same web worker handling your request , blocking it entirely until the task finishes. Every other user waiting for that worker would get no response until the import is done.

With Redis Queue, the web request does one thing: it pushes a job descriptor onto a Redis list and returns immediately. A separate background worker process picks up the job and executes it completely outside the web request lifecycle. The user sees the task start. Other users experience zero slowdown. The operation completes in the background and notifies the user when done.

frappe.enqueue(
    method="myapp.tasks.generate_and_email_report",
    queue="long",
    timeout=1200,
    report_name=report_name,
)

This is what makes it practical to send 10,000 emails, import 100,000 rows, or recalculate a full stock ledger without grinding ERPNext to a halt. The web tier stays free to serve users. The background tier handles the heavy lifting. Redis is the buffer between them that makes this possible.

Because jobs are stored in Redis rather than in process memory, they also survive server restarts , a Gunicorn restart does not wipe the queue. Multiple worker processes on multiple hosts can consume from the same queue, making it easy to scale background processing horizontally without changing any application code.

Three Queue Priorities
short
Quick tasks under 60 seconds , notification sends, cache invalidations, status updates.
default
Email dispatch, report generation, document submissions with side effects.
long
Data imports, PDF batch generation, stock ledger recalculations, heavy migrations.
06

Realtime Updates: Why the UI Stays Live Without Refreshing

When you run a data import in ERPNext, a progress bar updates in real time. When a background task completes, a notification appears on your desk instantly. When another user opens the same document, you see a live lock indicator. None of this requires you to refresh the page , and none of it would be possible without Redis pub/sub.

ERPNext runs two server-side processes: a Python application server and a Node.js SocketIO server. Your browser holds an open WebSocket connection to the Node.js process. When the Python server needs to push a state change to your browser , task completion, notification, lock event , it cannot reach the WebSocket directly. It publishes an event to a Redis channel using frappe.publish_realtime(). The Node.js server, subscribed to that channel, picks it up and pushes it to your browser immediately.

Event flow: Python Worker → publish_realtime() → Redis SocketIO Channel → Node.js SocketIO Server → Browser WebSocket

6.1 Why This Matters for Performance

❌ Without Redis (Polling)

The browser has to ask the server every 1 to 2 seconds , "is the import done yet?" With 50 users doing this simultaneously, that is 1,500 to 3,000 extra HTTP requests per minute hitting Gunicorn workers that are already busy serving real user requests.

Constant background noise. Slower responses for everyone during imports.
✅ With Redis (Push)

The Python worker pushes one event to Redis when each batch completes. Node.js delivers it to the right browser over the already-open WebSocket in under 10 ms. Gunicorn is not involved at all in delivering progress updates.

Zero polling overhead. Instant updates. No impact on web worker performance.
07

The Numbers: How Much Faster Does Redis Actually Make ERPNext?

All three Redis roles compound on each other. Caching reduces MariaDB query volume. The job queue reduces web worker saturation. Pub/sub eliminates polling load. The combined effect is that a server with Redis handling 50 concurrent users carries a MariaDB load comparable to 10 to 15 users without it. Here is what that looks like in concrete numbers:

Metric Without Redis With Redis
MariaDB queries per page render (50-user load) 40 to 80 queries 8 to 15 queries
Doctype metadata lookup latency 15 to 40 ms per call 0.2 to 1 ms per call
Permission check latency per record 5 to 15 ms under 1 ms
Dashboard chart query (repeated) 200 to 800 ms 1 to 5 ms from cache
Background job impact on web tier Blocks Gunicorn workers Fully isolated workers
Realtime event delivery Polling every 1 to 2s Push in under 10 ms
Measured on a 4-core / 8 GB server with 200 doctypes, 50 concurrent users, and MariaDB on the same host. Numbers vary by hardware, but the order-of-magnitude differences hold across deployments because they reflect structural query elimination, not hardware-specific tuning.
08

Getting the Most Out of Redis: Configuration and Tuning

Redis is already doing most of the work out of the box , but a few configuration choices determine whether it stays fast as your deployment grows. Misconfiguring Redis memory is the most common reason an ERPNext deployment that "has Redis" still feels slow.

8.1 Connection Configuration

Redis endpoints are declared in sites/common_site_config.json. A standard single-server setup:

{
  "redis_cache":        "redis://127.0.0.1:13000",
  "redis_queue":        "redis://127.0.0.1:11000",
  "redis_socketio":     "redis://127.0.0.1:13000",
  "background_workers": 4
}

8.2 How Much RAM to Give Redis

Under-allocating memory is the most common configuration mistake. When Redis runs out of space, it evicts cache entries , and every evicted entry means a request that falls back to MariaDB instead of being served from cache. The more evictions, the slower ERPNext gets.

Scale Concurrent Users Redis RAM Notes
Small 1 to 15 256 MB Single company, standard ERPNext modules
Medium 15 to 75 512 MB to 1 GB Multiple companies or heavy custom doctypes
Large 75 to 200+ 2 GB+ Consider dedicated Redis host; split cache / queue / socketio

8.3 Tuning Guidelines

  • 01Set maxmemory with maxmemory-policy allkeys-lru. Without this, Redis will consume all available RAM and then start refusing writes. With allkeys-lru, it gracefully evicts the least recently used entries, keeping the hot cache intact under memory pressure.
  • 02Set background_workers to your CPU core count, not higher. Each worker holds a MariaDB connection open. Over-allocating workers saturates the connection pool and slows down both background jobs and web requests at the same time.
  • 03Keep Redis on the same host or local network as the application server. Redis latency over a LAN is 0.1 to 0.5 ms. Over a WAN it becomes 5 to 50 ms , at which point the speed advantage over MariaDB disappears entirely and you have gained nothing.
  • 04Avoid running FLUSHALL during peak hours. A full cache clear forces every request to fall back to MariaDB simultaneously, creating a sudden query spike that can saturate the database for several minutes while the cache gradually rebuilds through normal traffic.
  • 05Track your cache hit rate with INFO stats via bench redis-console. A healthy ERPNext deployment has a hit rate above 85%. If it drops below 70%, your maxmemory limit is too low and cache entries are being evicted before they can be reused.
09

FAQs

Redis is running but ERPNext is still slow , why?
Running Redis and Redis working effectively are two different things. Check your cache hit rate: run bench redis-console, then INFO stats. If keyspace_misses is close to or higher than keyspace_hits, the cache is being evicted before entries can be reused. The fix is almost always increasing maxmemory and setting maxmemory-policy allkeys-lru.
How do I verify the cache is actually being used?
Run bench redis-console, then DBSIZE. An active production cache with 50 users typically holds 5,000 to 20,000 keys. A near-zero count during active usage means caching is not working , either the cache is being flushed too aggressively or the eviction policy is discarding entries immediately.
When should I move Redis to a dedicated server?
When you hit 75 or more concurrent users, or when INFO memory shows used_memory consistently near maxmemory. At that point the cache, queue, and pub/sub channels are competing for the same memory pool and evicting each other. Moving Redis Cache to a dedicated host with generous memory allocation gives you the biggest performance return.
Background jobs disappear after a server restart , what is wrong?
Redis does not persist data to disk by default, so jobs queued but not yet processed are lost when the server restarts. Enable RDB persistence on the Queue instance by adding save 900 1 to redis.conf. Do not enable AOF on the Cache instance , cache data is safe to lose on restart, and AOF adds unnecessary disk I/O with no benefit for ephemeral cached data.
Desk notifications and progress bars stopped updating , how do I fix it?
This is a pub/sub pipeline break. First confirm the SocketIO server is running with bench status. Then confirm Redis SocketIO is reachable: redis-cli -p 12311 ping. Verify redis_socketio in common_site_config.json points to the right host and port. If everything looks correct but events are still not arriving, restart the bench with bench restart and check logs/web.error.log for connection errors.
10

Conclusion

Redis makes ERPNext faster in ways that compound on each other. Caching cuts the number of MariaDB queries per page render from 40 to 80 down to 8 to 15. The job queue takes slow operations completely off the web thread so other users never feel them. Pub/sub replaces polling with instant push delivery, eliminating a constant source of background load. Together, these three mechanisms allow a well-configured ERPNext deployment to handle five times the concurrent users on the same hardware , simply because the right work reaches the right system.

If your ERPNext is slow and you have not looked at Redis memory allocation, cache hit rates, or worker configuration yet , start there. It is not the most glamorous infrastructure tuning, but it is consistently the one that makes the biggest visible difference to your users.

Related ERPNext resources