Skip to main content
Technical Guide

Odoo Performance Optimization Guide

Fix slow Odoo and boost efficiency with our comprehensive performance tuning guide. Learn PostgreSQL optimization, worker configuration, caching strategies, and more.

15-18 min readLast updated: January 2025Odoo 14-18 compatible

Common Performance Issues

Before diving into optimization techniques, it is important to recognize the symptoms of poor Odoo performance. These are the most common issues that indicate your Odoo instance needs tuning:

Slow Page Loads

Pages taking 3+ seconds to load, especially list views and dashboards

Report Timeouts

PDF reports and exports timing out or taking minutes to generate

High CPU Usage

Server CPU consistently above 80%, causing slowdowns across the system

Memory Exhaustion

Workers being killed due to memory limits, causing request failures

Database Lock Contention

Concurrent operations blocking each other, leading to timeouts

Slow Search Operations

Search and filter operations taking excessive time to complete

Diagnosing Bottlenecks

Before optimizing, you need to identify where the bottlenecks are. Here are the key diagnostic steps. If you're experiencing slowness specifically with Odoo.sh, check out our guide on fixing slow Odoo.sh performance.

1. Enable Odoo Profiling

Odoo 14+ includes a built-in profiler. Enable it in your configuration:

odoo.conf
[options]
log_level = debug
log_handler = :DEBUG

# For Odoo 15+
# Enable the profiling module and access via /web/profiler

2. Check PostgreSQL Slow Query Log

Enable slow query logging to identify expensive database operations:

postgresql.conf
# Log queries taking longer than 1 second
log_min_duration_statement = 1000

# Log all statements (use cautiously in production)
# log_statement = 'all'

# Enable query statistics
shared_preload_libraries = 'pg_stat_statements'

3. Monitor Server Resources

Use these commands to monitor system resources in real-time:

Terminal
# CPU and memory usage
htop

# Disk I/O monitoring
iotop

# Network connections
netstat -tuln | grep odoo

# PostgreSQL active connections
psql -c "SELECT count(*) FROM pg_stat_activity;"

4. Identify Heavy Modules

Some modules are known to cause performance issues:

  • mail/discuss: Can generate excessive database writes
  • stock: Complex inventory calculations on large datasets
  • mrp: Bill of materials explosions can be expensive
  • account: Large journal entries and reconciliation
  • Custom modules: Review for N+1 queries and missing indexes

PostgreSQL Optimization

PostgreSQL is the heart of Odoo performance. These configurations can dramatically improve query performance:

postgresql.conf - Recommended Settings
# Memory Configuration
shared_buffers = 256MB          # 25% of RAM (e.g., 2GB for 8GB server)
work_mem = 64MB                 # Per-operation memory
maintenance_work_mem = 256MB    # For VACUUM, CREATE INDEX
effective_cache_size = 1GB      # 50-75% of RAM

# SSD Optimization
random_page_cost = 1.1          # Lower for SSD (default 4.0 for HDD)
effective_io_concurrency = 200  # Higher for SSD

# Query Planner
default_statistics_target = 100 # More accurate query plans

# Connection Settings
max_connections = 100           # Tune based on workers
# Use PgBouncer for connection pooling in production

# Write-Ahead Log
wal_buffers = 16MB
checkpoint_completion_target = 0.9

# Autovacuum (aggressive for Odoo)
autovacuum = on
autovacuum_vacuum_scale_factor = 0.02
autovacuum_analyze_scale_factor = 0.01

Index Optimization

Identify missing indexes with this query:

-- Find tables with sequential scans (potential missing indexes)
SELECT schemaname, relname, seq_scan, seq_tup_read,
       idx_scan, idx_tup_fetch
FROM pg_stat_user_tables
WHERE seq_scan > 0
ORDER BY seq_tup_read DESC
LIMIT 20;

VACUUM and ANALYZE

Schedule regular maintenance for optimal performance:

# Full database maintenance (run during low traffic)
vacuumdb --all --analyze --verbose

# Specific table maintenance
psql -d odoo_db -c "VACUUM ANALYZE ir_attachment;"
psql -d odoo_db -c "VACUUM ANALYZE mail_message;"

# Cron job example (weekly)
0 3 * * 0 postgres vacuumdb --all --analyze >> /var/log/vacuum.log 2>&1

Connection Pooling with PgBouncer

PgBouncer reduces connection overhead for multi-worker setups:

pgbouncer.ini
[databases]
odoo = host=localhost port=5432 dbname=odoo_production

[pgbouncer]
listen_addr = 127.0.0.1
listen_port = 6432
auth_type = md5
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction
max_client_conn = 200
default_pool_size = 20

Worker Configuration

Proper worker configuration is critical for handling concurrent users efficiently. For containerized deployments, also check our Docker deployment guide for worker configuration in Docker environments.

odoo.conf - Worker Settings
[options]
# Worker Formula: (CPU cores * 2) + 1
# Example for 4-core server: (4 * 2) + 1 = 9 workers
workers = 9

# Cron worker (separate from HTTP workers)
max_cron_threads = 2

# Memory Limits (in bytes)
limit_memory_hard = 2684354560  # 2.5GB - worker killed above this
limit_memory_soft = 2147483648  # 2GB - worker recycled above this

# Request Limits
limit_request = 8192            # Max requests before worker recycled
limit_time_cpu = 600            # Max CPU seconds per request
limit_time_real = 1200          # Max wall-clock seconds per request

# Longpolling (for live chat, notifications)
longpolling_port = 8072
ParameterDescriptionRecommendation
workersNumber of HTTP worker processes(CPU cores * 2) + 1
max_cron_threadsThreads for scheduled actions1-2 (rarely need more)
limit_memory_hardWorker killed when exceeded2.5GB (adjust for RAM)
limit_memory_softWorker recycled after request2GB (80% of hard limit)
limit_time_cpuMax CPU time per request600s (increase for heavy reports)
limit_time_realMax wall-clock time per request1200s (2x CPU limit)

Memory Calculation

Ensure you have enough RAM: (workers * limit_memory_hard) + PostgreSQL memory + OS overhead. For 9 workers with 2.5GB limit, you need at least 24GB RAM.

Caching Strategies

Implementing proper caching can dramatically reduce database load and improve response times:

Redis for Session Storage

Replace file-based sessions with Redis for better performance in multi-worker setups:

odoo.conf
# Redis session backend (requires redis Python package)
session_redis_host = localhost
session_redis_port = 6379
session_redis_db = 0
session_redis_prefix = odoo_session:

Query Caching with ORM Cache

Odoo has built-in caching for computed fields. Use it effectively:

Python model example
from odoo import api, fields, models

class ProductProduct(models.Model):
    _inherit = 'product.product'

    # Use store=True for frequently accessed computed fields
    total_sales = fields.Float(
        compute='_compute_total_sales',
        store=True  # Caches result in database
    )

    @api.depends('sale_order_line_ids.qty_delivered')
    def _compute_total_sales(self):
        for product in self:
            product.total_sales = sum(
                line.qty_delivered
                for line in product.sale_order_line_ids
            )

Static Asset Caching with Nginx

Configure Nginx to cache static assets and reduce Odoo load:

nginx.conf
# Cache static assets for 1 year
location ~* /web/static/ {
    proxy_pass http://odoo;
    proxy_cache_valid 200 365d;
    expires 365d;
    add_header Cache-Control "public, immutable";
}

# Cache attachments
location ~* /web/content/ {
    proxy_pass http://odoo;
    proxy_cache_valid 200 30d;
    expires 30d;
}

CDN for Static Assets

Use a CDN like Cloudflare or AWS CloudFront to serve static assets closer to users. This reduces latency and offloads traffic from your server.

  • Configure CDN to cache /web/static/* paths
  • Set appropriate cache headers (1 year for versioned assets)
  • Enable compression (gzip/brotli) at CDN level
  • Use CDN for images and attachments where appropriate

Frontend Optimization

Optimize the frontend to improve perceived performance and reduce server load:

Asset Bundling and Minification

Odoo automatically bundles assets in production mode. Ensure you are running with proper settings:

Production settings
# Run Odoo in production mode (not --dev mode)
./odoo-bin -c /etc/odoo/odoo.conf

# Regenerate assets after updates
./odoo-bin -c /etc/odoo/odoo.conf -d your_db --update=base

# Clear asset cache via SQL if needed
psql -d your_db -c "DELETE FROM ir_attachment WHERE name LIKE 'web.assets%';"

Lazy Loading and Pagination

Optimize list views and related fields:

  • Set reasonable limit on tree views (default 80 is often too high)
  • Use @api.onchange sparingly - each triggers a server round-trip
  • Avoid loading Many2one fields with large domains
  • Use prefetch_fields to optimize ORM queries

Reduce Unnecessary API Calls

Common causes of excessive API calls:

  • Chatter/mail thread loading on every page
  • Status bar widgets with complex domain filters
  • Dashboard widgets polling too frequently
  • Automated actions triggering on every record change

Hardware Recommendations

Choose the right hardware based on your user count and workload. Need help calculating your exact requirements? Use our server requirements calculator to get personalized recommendations.

Concurrent UsersRAMCPUStorage
1-10 users4GB2 vCPU50GB SSD
10-50 users8GB4 vCPU100GB SSD
50-200 users16GB8 vCPU250GB SSD
200+ users32GB+16+ vCPU500GB+ SSD

Additional Considerations

  • SSD is mandatory - NVMe SSDs provide best PostgreSQL performance
  • Separate database server - For 50+ users, consider dedicated PostgreSQL server
  • Network latency - Place database and application servers in same datacenter
  • Backup storage - Plan for 2-3x database size for backup retention

Monitoring Setup

Set up proper monitoring to catch performance issues before they impact users:

Prometheus + Grafana Setup

The recommended monitoring stack for Odoo deployments:

docker-compose.yml (monitoring stack)
version: '3.8'
services:
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  grafana:
    image: grafana/grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=secure_password

  node-exporter:
    image: prom/node-exporter
    ports:
      - "9100:9100"

  postgres-exporter:
    image: prometheuscommunity/postgres-exporter
    environment:
      DATA_SOURCE_NAME: "postgresql://user:pass@db:5432/odoo?sslmode=disable"
    ports:
      - "9187:9187"

Key Metrics to Monitor

System Metrics

  • CPU utilization (target: under 80%)
  • Memory usage (watch for OOM)
  • Disk I/O wait (target: under 10%)
  • Network throughput

PostgreSQL Metrics

  • Active connections
  • Query duration (p95, p99)
  • Cache hit ratio (target: over 99%)
  • Replication lag (if applicable)

Odoo Metrics

  • Request latency (p50, p95)
  • Error rate (5xx responses)
  • Worker memory usage
  • Longpolling connections

Business Metrics

  • Active users count
  • Cron job execution time
  • Email queue size
  • Report generation time

Recommended Alert Thresholds

MetricWarningCritical
CPU Usageover 70%over 90%
Memory Usageover 80%over 95%
Disk Usageover 75%over 90%
Request Latency (p95)over 2sover 5s
Error Rateover 1%over 5%

Performance Checklist

Use this checklist to ensure you have covered all optimization areas:

Database

Application

Caching

Frontend

Maintenance

Monitoring

Tip: Bookmark this page to track your optimization progress

Let OEC.sh Handle Performance Optimization

All of these optimizations are handled automatically when you deploy Odoo on OEC.sh. Focus on your business, not server tuning.

Pre-optimized PostgreSQL configuration
Auto-scaled workers based on traffic
Built-in Redis caching
CDN integration for static assets
24/7 performance monitoring
Automatic VACUUM scheduling
SSD storage on all deployments
Expert support when you need it

Frequently Asked Questions

Why is my Odoo so slow?

Slow Odoo performance typically stems from one or more of these issues: insufficient hardware resources (RAM, CPU), unoptimized PostgreSQL configuration, too few or too many workers, missing database indexes, heavy custom modules, or lack of caching. Start by checking your server resource utilization during peak usage to identify the primary bottleneck.

How many workers should I configure for Odoo?

The recommended formula is: workers = (CPU cores * 2) + 1. For example, a 4-core server should run 9 workers. However, this depends on your workload. For CPU-intensive operations like report generation, use fewer workers. Always monitor memory usage, as each worker consumes approximately 150-300MB RAM.

What's the best PostgreSQL config for Odoo?

The best PostgreSQL configuration for Odoo includes: shared_buffers set to 25% of RAM, effective_cache_size at 50-75% of RAM, work_mem at 64MB, and random_page_cost at 1.1 for SSD storage. Also enable aggressive autovacuum settings and use connection pooling with PgBouncer for multi-worker setups. These settings significantly improve query performance and database efficiency.

Should I use Redis with Odoo?

Yes, Redis significantly improves Odoo performance, especially in multi-worker setups. Use Redis for session storage (eliminates file-based session locking), as a cache backend for computed fields and method caching, and for queue management with Odoo Queue Job module. Configure Redis with appropriate memory limits and eviction policies.

How much RAM does Odoo need?

RAM requirements depend on your user count and workload. For 1-10 users, allocate at least 4GB RAM. For 10-50 users, you need 8GB minimum. For 50-200 users, plan for 16GB. Calculate RAM as: (workers × 250MB) + PostgreSQL memory + OS overhead. For 9 workers, you need at least 8GB RAM, but 16GB is recommended for production workloads with headroom.

How to diagnose Odoo performance issues?

Start by enabling Odoo profiling with log_level = debug and PostgreSQL slow query logging with log_min_duration_statement = 1000. Monitor server resources using htop for CPU/memory, iotop for disk I/O, and check PostgreSQL active connections. Use the Odoo profiler module (Odoo 15+) to identify slow requests. Look for N+1 queries, missing indexes, and heavy custom modules.

Does Odoo need SSD storage?

Yes, SSD storage is strongly recommended for Odoo deployments. PostgreSQL performance is heavily dependent on disk I/O, especially for complex queries and report generation. SSDs provide 10-100x faster random read/write speeds compared to HDDs. Set random_page_cost to 1.1 in PostgreSQL when using SSDs.

How often should I run VACUUM on PostgreSQL?

For Odoo databases, configure autovacuum to run continuously with aggressive settings. Additionally, schedule a weekly VACUUM ANALYZE during low-traffic periods to reclaim space and update statistics. For heavily-updated tables (like ir_attachment, mail_message), consider more frequent manual VACUUM operations.

Ready to Deploy a Fast Odoo Instance?

Skip the manual optimization. OEC.sh provides pre-tuned Odoo hosting with all these optimizations built in.