If you only remember one thing from this post: more workers is better, and RAM is what decides how many you can have. Everything else is detail./
Here is the short version:
Take your server's total RAM.
Subtract what PostgreSQL needs (if it runs on the same server) and what the OS needs.
Divide what's left by the RAM you allow per worker: 1 GB is a safe ceiling, 512 MB works for light usage.
That's your worker count. The rest of this post explains why this works, what a worker actually is, and how to sanity-check the result against your user count.
What is an Odoo worker?
When Odoo runs in multi-processing mode (workers = N in the config), it spawns N separate worker processes. Each worker handles one HTTP request at a time. A page load in Odoo is not one request, the web client fires a burst of RPC calls, asset requests, and long-polling connections for every screen your users touch.
So the worker count is, in practice, your ceiling on requests per second. Two workers means two requests being processed at any instant; everything else waits in line. That queue is what users experience as "Odoo is slow today."
This is why the goal is simple: run as many workers as your machine can hold.
The only real limit is RAM
You will sometimes see a CPU-based rule of thumb floating around
(workers = cores × 2 + 1)
It's a fine starting point, but on real Odoo servers, RAM runs out long before CPU does. Workers spend most of their time waiting on the database and on I/O, not burning CPU but each one permanently occupies memory. So size on RAM, and let the CPU rule be a tiebreaker, not the constraint.
Step 1 Compute your available RAM
Start from the machine's total RAM and subtract everything that isn't Odoo:
PostgreSQL, if it runs on the same server. A common setup reserves roughly 25–40% of the machine for it (shared_buffers plus working memory). Check what yours actually uses.
The operating system and whatever else runs on the box (monitoring agents, nginx, etc.). Budget 1–2 GB.
available_ram = total_ram − postgres_ram − os_ram
If PostgreSQL lives on its own server, skip that subtraction, one of several good reasons to separate them as you grow.
Step 2 Decide the RAM budget per worker
Each worker needs a memory ceiling (limit_memory_hard / limit_memory_soft in the config). In practice:
1 GB per worker is the comfortable default. Nearly every workload fits.
512 MB per worker works if your usage is light: standard modules, no heavy reports, no big imports/exports. You get twice the workers from the same RAM, but a single heavy request can hit the ceiling and get recycled.
If you don't know your workload yet, start at 1 GB. You can lower it later once you've watched real memory usage.
Don't forget the cron workers
workers = N only counts HTTP workers. Odoo also starts cron workers, 2 by default (max_cron_threads), which run your scheduled jobs: mail queues, automated actions, stock recomputations. They consume RAM exactly like an HTTP worker, and a heavy scheduled job can easily use the full per-worker budget.
So reserve room for them before dividing. (Odoo also runs one gevent/websocket process for live features, small, but it comes out of the same pool.)
Step 3 Divide
workers = (available_ram − cron_workers × ram_per_worker) ÷ ram_per_worker
Worked example. A 16 GB server running PostgreSQL locally:
Total RAM |
16 GB |
− PostgreSQL |
4 GB |
− OS and services |
2 GB |
Available for Odoo |
10 GB |
− 2 cron workers at 1 GB |
2 GB |
Left for HTTP workers |
8 GB |
HTTP workers at 1 GB each |
8 workers |
Same machine, same cost, the only decision is the per-worker budget.
Sanity check: workers vs. user count
Odoo's sizing guidance suggests roughly one worker per ~25 internal users. Treat that as a way to estimate the machine you need, not as a target to configure down to.
Two reasons it's only a rough guide:
Workload varies wildly by who those users are. Twenty-five people occasionally logging time behave nothing like twenty-five sales reps hammering the CRM all day, or a warehouse team scanning barcodes every few seconds.
Odoo is chatty. Every user interaction fans out into multiple requests. Extra workers absorb these bursts, which is what keeps the interface feeling instant.
So use the user count to pick a machine size, then fill that machine with as many workers as its RAM allows. If the formula gives you 10 workers for 50 users, run 10 workers, not 2. Idle workers cost you nothing; missing workers cost you queue time on every click.
Quick reference
available_ram = total_ram − postgres_ram − os_ram
workers = (available_ram − cron_workers × ram_per_worker) ÷ ram_per_worker
ram_per_worker: 1 GB (safe) or 512 MB (light workloads)
cron_workers: 2 by default (max_cron_threads) — they use RAM too
machine sizing: ~1 worker per 25 internal users, then round up
principle: as many workers as the RAM allows
Or skip the arithmetic
If you'd rather not manage worker configs, memory limits, and PostgreSQL tuning at all: every Skysize plan comes with a fixed worker allocation sized for its tier, 3 workers on Launch, 6 on Scale, 12 on Business, on infrastructure we tune and monitor for you, for both Odoo Community and Enterprise.
See what's included in each plan.
Start a free 7-day trial, no credit card, and your backups are downloadable anytime, so you're never locked in.