In this article

Shared hosting and managed Odoo platforms work fine at small scale but develop predictable limitations as deployments grow. This article covers Odoo’s infrastructure requirements, how to size bare metal hardware for real workloads, and how OpenMetal’s private networking enables a clean app-and-database split when you need it.


There’s a predictable inflection point in Odoo deployments where two problems arrive at the same time: the per-user infrastructure cost starts to feel disproportionate, and performance gets inconsistent in ways that trace back to a database the team has no access to tune.

It usually hits somewhere between 30 and 100 named users. It arrives earlier if MRP, ecommerce, or large-scale accounting modules are running. And it tends to show up as slowdowns during batch operations and report generation, which are exactly the operations that matter most to finance and operations teams.

Dedicated bare metal addresses both sides of it. Infrastructure cost becomes fixed regardless of headcount. PostgreSQL moves to hardware the team controls and can configure properly.

What Makes Odoo Demanding on Infrastructure

Odoo is a Python application that uses PostgreSQL as its only supported database. Every action in the system, from a sales order to an inventory adjustment to a scheduled automation, generates database activity. This is different from applications that can offload reads to caches or use lighter-weight databases for parts of their stack. In Odoo, everything goes through PostgreSQL.

The application runs in multi-process mode in production, where the number of concurrent request handlers is set by the workers parameter in odoo.conf. Odoo’s documentation gives the canonical formula:

workers = (CPU cores × 2) + 1

Each worker handles one request at a time. Workers are your actual concurrency ceiling, not the CPU core count itself. Each worker consumes roughly 150 to 300 MB of RAM at rest and can spike well past 1 GB during heavy operations like inventory valuations, financial closings, or large report exports. On an undersized server, this is where performance collapses: workers exhaust available RAM, the OS starts swapping, and response times degrade from seconds to minutes.

PostgreSQL compounds this. The database performs best when its working set fits in memory, controlled by the shared_buffers setting in postgresql.conf. The standard recommendation is to allocate 25% of total system RAM to shared_buffers. On a server with 8 GB of RAM, that is 2 GB for the database buffer pool. On a server with 256 GB, it is 64 GB, which means most active tables and indexes stay in memory rather than hitting storage for every query. This is one of the most impactful single-configuration changes for Odoo performance, and it requires access to the PostgreSQL configuration file, which managed platforms like Odoo.sh do not provide.

Heavy modules change the resource math significantly. A basic CRM deployment is far lighter than one running manufacturing (MRP), ecommerce, or large-scale accounting. Adding MRP or ecommerce can roughly double the CPU and RAM requirements for the same number of concurrent users. If your deployment includes these modules, size for it from the start.

Sizing by Concurrent Users, Not Named Users

The most common Odoo sizing mistake is using the named user count rather than concurrent users. A 100-person company rarely has 100 people actively using Odoo at the same moment. A realistic estimate is 30 to 50 percent of named users being concurrent during peak hours, lower in shift-based or field-heavy operations.

For production Odoo deployments running standard modules, the working baselines are:

  • Up to 25 concurrent users: 4 dedicated cores, 8 GB RAM
  • 25 to 60 concurrent users: 8 dedicated cores, 16 GB RAM
  • 60 to 100 concurrent users: 16 dedicated cores, 32 GB RAM (database separation recommended at this scale)
  • Above 100 concurrent users: split application and database servers, scale each independently

These numbers assume standard modules. Add 50 to 100% headroom if MRP, ecommerce, or large-scale batch reporting are part of the deployment.

Storage sizing is dominated by the filestore, not the database. The Odoo filestore holds attachments, documents, product images, and other binary content. For businesses handling significant document volume, plan 2 to 5 GB of filestore growth per active user per year. The database itself grows slowly by comparison. NVMe storage handles both well: the fast random I/O that PostgreSQL needs for index lookups and the throughput that large file operations require.

Dedicated Cores vs. vCPUs for PostgreSQL

PostgreSQL is one of the workloads most sensitive to CPU contention. It relies on predictable I/O scheduling and CPU time for its vacuum processes, autovacuum, and query execution. On a shared cloud instance where vCPUs are time-sliced across tenants, autovacuum and background workers compete with your query workload for CPU time. The practical result is inconsistent query latency, especially under load.

Dedicated bare metal gives PostgreSQL exclusive access to physical cores. There is no time-sharing with neighboring tenants. The I/O scheduler services only your workload. This matters most for the operations that typically cause complaints in shared environments: large reports, inventory valuations, financial period closings, and MRP scheduling runs.

It also matters for PostgreSQL configuration. You can set shared_buffers, work_mem, effective_cache_size, and autovacuum parameters to match your actual hardware and workload. On Odoo.sh, PostgreSQL tuning is not available to customers. On a VPS with 8 GB of RAM shared with other workloads, setting shared_buffers to 25% of RAM leaves limited headroom for everything else. On a dedicated bare metal server with 256 GB of RAM, PostgreSQL can hold a large working set in memory without competing with the application layer for resources.

Single Server vs. Splitting App and Database

For most Odoo deployments up to around 60 to 75 concurrent users, running the application server and PostgreSQL on the same machine is straightforward to manage and performs well with proper tuning. Both processes have access to the full RAM pool, and there is no network overhead between the application and the database.

Past that scale, or when running heavy modules with frequent large queries, moving PostgreSQL to a dedicated server becomes worthwhile. A dedicated database server lets you size memory specifically for PostgreSQL’s working set, tune the kernel and storage scheduler for database I/O, and scale the application and database tiers independently as load grows.

On OpenMetal, separating Odoo and PostgreSQL onto two bare metal servers is straightforward. Both servers sit on the same dedicated customer VLAN, with 20 Gbps of unmetered private bandwidth between them. Application-to-database traffic stays entirely on the private network, never touching a public interface. Latency between servers on the same private network is low enough that the split adds negligible overhead while giving you independent scaling and resource control for each tier.

A practical configuration for a 75 to 150 concurrent user deployment:

  • Odoo application server: Large v4 or Large v5 (32 cores, 512 GB RAM). Workers set to 65 (32 cores × 2 + 1). Application RAM handles worker memory peaks and OS overhead. Connects to the database over the private VLAN.
  • PostgreSQL server: Medium v4 or Medium v5 (24 cores, 256 GB RAM). shared_buffers set to 64 GB (25% of RAM). effective_cache_size set to 192 GB. The 6.4 TB NVMe on the Medium v5 handles the filestore and write-ahead log with room to grow.

Hardware That Fits Odoo Workloads

Medium v4 or Medium v5 (24 cores, 256 GB RAM, 6.4 TB NVMe) suits small to medium deployments running standard modules: up to roughly 50 to 60 concurrent users with CRM, sales, inventory, and accounting. At 24 cores, you get 49 workers by the formula, which covers that concurrency range comfortably. The 256 GB RAM gives PostgreSQL 64 GB of shared_buffers with ample headroom for workers. For a deployment that is also the PostgreSQL server, this tier handles most SMB use cases well.

Large v4 or Large v5 (32 cores, 512 GB RAM, 12.8 TB NVMe) fits medium deployments running heavier modules, or serves as the application server in a split configuration. At 32 cores you get 65 workers. The 512 GB RAM supports both a well-configured PostgreSQL instance and the worker memory footprint of a larger Odoo deployment without contention. The 12.8 TB NVMe handles even document-heavy filestorage growth for years without requiring additional storage.

XL v4 or XL v5 (64 cores, 1 TB RAM, 25.6 TB NVMe) fits large deployments or serves as a dedicated PostgreSQL server for high-concurrency environments. As a PostgreSQL host, 1 TB of RAM allows a 256 GB shared_buffers allocation, which can hold a substantial working set for large databases entirely in memory. This configuration is appropriate for deployments running MRP at scale, multi-company environments with large transaction volumes, or organizations that want significant headroom before needing to scale out.

Current v5 hardware is available in Ashburn and Los Angeles. v4 is available across all locations: Los Angeles, Ashburn, Amsterdam, and Singapore. Full specs are on the hardware details page.

Who This Fits

Growing SMBs and mid-market companies running Odoo Enterprise

The per-user licensing cost of Odoo Enterprise is fixed regardless of infrastructure. Moving infrastructure to dedicated bare metal separates the licensing cost from the infrastructure cost and makes the latter predictable and fixed.

Teams running MRP, ecommerce, or large-scale accounting modules

These modules generate heavy database activity. Dedicated hardware and a tunable PostgreSQL instance are the practical path to reliable performance at this level of usage.

Companies that have outgrown Odoo.sh or VPS hosting

Odoo.sh is a well-designed managed platform with a real limitation: you cannot tune PostgreSQL. If your performance issues trace back to the database layer and you need to change shared_buffers, work_mem, or autovacuum behavior, you need infrastructure you control.

Odoo Community deployments at scale

Odoo Community is open source with no per-user license cost. At higher user counts, the only cost is infrastructure. Dedicated bare metal at a fixed monthly rate is the natural fit for community deployments that have grown beyond shared hosting.

Who This Doesn’t Fit

Small deployments with light module usage

If you have 10 to 15 users running basic CRM and sales, a VPS or Odoo.sh handles this well and the operational simplicity is worth the tradeoff. Bare metal becomes worthwhile when you are outgrowing those environments.

Teams without Linux administration experience

Running Odoo on bare metal means owning the OS, PostgreSQL configuration, Nginx setup, SSL, backups, and updates. This is standard Linux sysadmin work, but if your team does not have that capacity, a managed Odoo hosting provider is a more practical choice.

Deployments that need Odoo.sh-specific features

Odoo.sh provides built-in staging environments, one-click branch deployments, and tight integration with Odoo’s update infrastructure. If those features are central to your development workflow, a self-hosted deployment requires replicating that workflow yourself.

Frequently Asked Questions

Why does Odoo require PostgreSQL specifically?

Odoo’s ORM and all of its modules are built to PostgreSQL’s feature set, including specific data types, full-text search capabilities, and transactional behavior. There is no support for MySQL, MariaDB, or other databases. PostgreSQL is a hard dependency.

How many Odoo workers should I configure?

Odoo’s deployment documentation gives the formula: workers = (CPU cores × 2) + 1. Each worker handles one request at a time and consumes 150 to 300 MB of RAM at rest. Size your total RAM to handle the expected number of workers at peak, with headroom for PostgreSQL’s shared_buffers allocation.

How much RAM should PostgreSQL receive?

The standard recommendation is to set PostgreSQL’s shared_buffers to 25% of total system RAM. On a server with 256 GB of RAM, that is 64 GB. effective_cache_size is typically set to 75% of RAM as a hint to the query planner. These values require access to postgresql.conf, which is why managed platforms that restrict database configuration can limit performance at scale.

When should I move PostgreSQL to a separate server?

As a rough guide, splitting the application and database servers becomes worthwhile somewhere past 60 to 75 concurrent users, or earlier if heavy modules like MRP generate large batch queries that saturate the database layer. On OpenMetal, both servers connect over a 20 Gbps unmetered private network, so the inter-server latency is low and the bandwidth is not a bottleneck.

Does Odoo Community work the same way on bare metal as Odoo Enterprise?

From an infrastructure standpoint, yes. Both editions run on the same Python/PostgreSQL/Nginx stack and use the same worker model and configuration files. The difference is that Enterprise requires a valid subscription and includes additional modules not in Community. Infrastructure sizing and tuning applies equally to both.

Can I run Odoo alongside other workloads on the same bare metal server?

Yes. A common configuration is running Odoo alongside a reverse proxy, a mail server, or other internal services on the same host, particularly on larger servers where resources are not fully consumed by Odoo. The main constraint is ensuring PostgreSQL has the RAM allocation it needs without contention from other memory-intensive processes.

Can I use Ceph storage with Odoo?

Odoo’s filestore is a filesystem-based directory. A Ceph-backed volume presented as a block device and formatted with a standard filesystem works as a filestore location. This becomes relevant in multi-server configurations where the filestore needs to be accessible from multiple application nodes, or in deployments that want the data redundancy Ceph provides.


At the point where Odoo’s infrastructure cost and performance have become constraints, dedicated bare metal changes both. Infrastructure cost becomes fixed. PostgreSQL becomes fully tunable. The hardware is sized for your actual workload rather than a shared-resource approximation of it.

To scope a configuration for your Odoo deployment, talk to the team or apply for a proof of concept.


Chat With Our Team

We’re available to answer questions and provide information.

Reach Out

Schedule a Consultation

Get a deeper assessment and discuss your unique requirements.

Schedule Consultation

Try It Out

Take a peek under the hood of our cloud platform or launch a trial.

Trial Options

 

 

 Read More on the OpenMetal Blog

Why Growing Businesses Self-Host Odoo ERP on Dedicated Bare Metal

Sep 23, 2026

As Odoo deployments grow in users and modules, shared cloud hosting and managed platforms hit performance and cost ceilings. This article covers why dedicated bare metal changes the picture, how to size hardware against Odoo’s actual resource model, and when to split the application and database onto separate servers.

Running Windows Server and Hyper-V on Dedicated Bare Metal

Sep 22, 2026

OpenMetal bare metal servers support custom OS installs via IPMI, including Windows Server. This article covers the installation path, edition selection and core licensing on dedicated hardware, Hyper-V setup for VM consolidation, and which hardware configurations suit different Windows workloads.

Self-Hosting Temporal Is a Postgres and Private Networking Decision Before Anything Else

Sep 17, 2026

How Temporal Cloud’s per-action billing model works and where it compounds, what the official Temporal documentation says self-hosted deployments require, the infrastructure stack a production cluster needs, and where OpenMetal’s bare metal fits into that.

Your LangGraph Agent Loses Everything When the Server Restarts

Sep 15, 2026

What LangGraph manages and what it explicitly does not, why MemorySaver is not a production checkpointer, what PostgresSaver requires from your infrastructure, the compute profile of long-running agent workflows, and where dedicated bare metal fits.

What the EU AI Act’s Article 12 Requires From Your Log Infrastructure

Sep 14, 2026

What Article 12 of the EU AI Act actually requires, why the obligation is an infrastructure problem before it is a software problem, what compliant log storage needs to look like in practice, the current enforcement timeline, and how private cloud in the EU addresses the requirement.

A Technical Guide to Every CPU Generation in OpenMetal’s Lineup

Sep 04, 2026

The four distinct Intel Xeon generations running across OpenMetal’s bare metal and hosted private cloud lineup, what actually changes between them beyond core count, and which generation fits which kind of workload, including where confidential computing eligibility depends on generation and hardware configuration together.

Why Shared HPC Access Gets Unpredictable for Life Sciences Computing

Sep 02, 2026

We look at why shared, allocation-based HPC access becomes a real operational problem for life sciences computational research, what changes on dedicated infrastructure that you administer yourself, and how to structure a transition that scales up gradually rather than requiring a large upfront commitment.

Infrastructure for Real-Time Bidding and Programmatic Advertising Platforms

Aug 21, 2026

We look at the real timing constraint behind real-time bidding auctions, why shared cloud infrastructure quietly eats into that budget through virtualization and cross-zone network hops, and where dedicated bare metal removes that variance directly.

Index-Time and Query-Time Account Discovery Want Different Memory

Aug 21, 2026

An account-intelligence system that pre-embeds ten million companies into a resident vector index, and one that dispatches agents to research those same companies live on demand, look like the same

Utilization Is a Tenancy Decision: Why Sustained MFU Lives Below the Kernel

Aug 13, 2026

On latency-bound inference, the Model FLOPs Utilization your optimization stack can actually hold is capped by who else shares the box, not by the kernel that runs on it. Sustained