For sure, everyone who has observed his/her Odoo system working under real users' pressure knows very well how the difference between theory and practice can sometimes be significant. And once the Odoo slows down, the most critical area to analyze first should be the configuration of the number of workers — something that often turns out to be very important.
What is really going on behind the workers? What numbers would be appropriate for certain types of setups? Let's review all of these things in more detail.
What Is Actually a Worker?
Here is a simple definition of what workers are in Odoo 19: a worker is a standalone process that processes a user's request, communicates with the database, and returns a response without using any resources used by other workers, which run simultaneously with it.
In development, Odoo uses a single process model, which works fine for developers working alone. However, as soon as you shift to multi-users' operation environment in production, you have to switch to multi-processes.
Not all workers do the same job, either. Behind the scenes, they split into three types:
- HTTP workers — these handle the day-to-day stuff: form views, API calls, UI interactions
- Cron workers — responsible for scheduled background tasks like automated invoicing or syncing data
- Longpolling workers — the ones keeping real-time features alive, like notifications and live chat
Enabling worker mode is straightforward:
workers = 8
Set this to 0 and you're back to single-threaded mode — fine for local development, but not something you want in production.
Additional Workers Don’t Necessarily Make Things Better
Here is when most developers make their first mistake. The myth states that increasing the number of workers in a bottlenecked system is the right solution. While it helps in some cases, it is often quite the opposite.
In case there are too few workers, users will notice delays – messages are queued for processing. In case there are too many workers, memory consumption will become extremely high and your processes will constantly be recycled while the program “runs” horribly slow.
What matters here is balancing your amount of workers against what your server can handle.
How to Calculate a Starting Point
A widely used starting formula is:
workers = (CPU cores × 2) + 1
On a 4-core machine, that gives you 9 workers. It's a reasonable baseline because it accounts for the typical mix of CPU-intensive operations and time spent waiting on I/O.
That said, treat it as a starting point, not a final answer. If your CPU is sitting near 100% consistently, pull workers down. If CPU has headroom but users are still complaining about slowness, there's room to push it up.
Memory: The Other Half of the Equation
Each worker loads its own copy of Python, whatever modules you're running, and query results. That adds up quickly.
Odoo gives you two memory parameters to work with:
limit_memory_soft = 640000000
limit_memory_hard = 768000000
Hitting the soft limit triggers a graceful recycling of the worker after it finishes its current request. Hitting the hard limit kills it immediately. Both are there to prevent a single runaway worker from eating all available memory.
In real-world terms, expect each worker to use somewhere between 500 MB and 600 MB. Running 8 workers means budgeting 4–5 GB just for Odoo — and that's before PostgreSQL and the OS take their share. If you don't have that headroom, you'll start swapping to disk, and at that point performance drops off a cliff.
Know Your Workload Type
Whether your bottleneck is CPU or I/O changes how you should approach tuning.
CPU-heavy operations — generating large PDF reports, running complex calculations inside custom modules, or processing big data sets — don't benefit much from additional workers. If the CPU is already maxed out, more workers just create more contention for the same resource.
I/O-heavy workloads are different. When workers are spending most of their time waiting — for a database query to return, for an external API to respond, for a network call to complete — having more workers running in parallel means that wait time is spent productively rather than idly.
Understanding which category your Odoo usage falls into matters more than any formula.
Configuring Worker Types
HTTP Workers
These are the main workers serving user requests.
workers = 8
The number here should be based on CPU and memory capacity.
Cron Workers
Scheduled jobs are handled using cron threads. By default, cron jobs share worker resources, but you can control concurrency:
max_cron_threads = 2
If you have heavy scheduled operations such as bulk updates or integrations, increasing this value can prevent delays.
Longpolling Worker
Longpolling is used for real-time communication features.
longpolling_port = 8072
In production setups, this is usually routed separately through the reverse proxy to avoid blocking normal HTTP workers.
Time Limit Configuration
To prevent workers from getting stuck on long requests, Odoo provides execution limits:
limit_time_cpu = 60
limit_time_real = 120
CPU time is the actual processing time, while real time includes waiting time.
If a request exceeds these limits, the worker is restarted. This ensures that one bad request does not block the system.
Example Production Configuration
workers = 8
max_cron_threads = 2
limit_memory_soft = 640000000
limit_memory_hard = 768000000
limit_time_cpu = 60
limit_time_real = 120
longpolling_port = 8072
proxy_mode = True
This configuration works well for a mid-range server with 4 CPU cores and 8 GB RAM, assuming moderate user load.
Don't Forget the Reverse Proxy
Odoo in production almost always sits behind Nginx or a similar reverse proxy. The proxy handles connection management, SSL termination, and can significantly improve efficiency when configured properly.
At minimum:
proxy_mode = True
Route long polling through a separate location block, and use keep-alive to reduce the overhead of constantly opening and closing connections. A well-tuned proxy can make a real difference even before you touch a single worker setting.
Monitoring and Fine-Tuning
Initial configuration is only the first step. Continuous monitoring is required to get stable performance.
Things to track:
- CPU usage patterns during peak hours
- Memory usage per worker
- Number of worker restarts
- Average response time
Logs provide useful insights. Common warnings include:
- Memory limit exceeded
- Worker timeout
- Slow SQL queries
These indicators help identify whether the issue is related to workers, database performance, or code inefficiencies.
Common Issues with Worker Setup
- Over-provision of labour
This is one of the most common errors that are made. More workers does not necessarily mean a performance increase.
- To forget about database performance
PostgreSQL won’t fix slow queries with more workers, and may make them worse.
- No time limits
Without a deadline, a single request can imprison the worker forever.
- Production runs in single-threaded mode
The system will have concurrency issues with few users.
Real-world Scenario
Consider a system with:
- 6 CPU cores
- 16 GB RAM
- Around 50 concurrent users
Initial configuration:
workers = 13
Observed issues:
- High memory usage
- Frequent slow responses during peak time
After tuning:
- Reduced workers to 9
- Adjusted memory limits
- Optimized heavy cron jobs
Result:
- Stable memory usage
- Better response times
- Reduced worker restarts
The performance of the whole Odoo 19 application largely depends on the configuration of the worker. The configuration should be different depending on various scenarios. Therefore, the best option would be to try out some configurations and see what happens based on observations.
A good configuration is one where the CPU and memory are fully utilized without destabilizing the entire Odoo platform.
To read more about How to Install Odoo 19 on Ubuntu 24 LTS Server, refer to our blog How to Install Odoo 19 on Ubuntu 24 LTS Server.