Files
odoo-erp/README_odoo18.md
2026-09-11 07:19:23 +07:00

21 KiB

Odoo Docker Development Environment

This project provides a Docker-based development environment for running Odoo using local Odoo core source code and separate custom addons.

This setup is useful for:

  • Odoo custom module development
  • Studying Odoo core source code
  • Keeping custom addons in a separate Git repository
  • Running Odoo and PostgreSQL with Docker Compose
  • Managing multiple Odoo versions cleanly

Project Structure

Recommended folder structure:

odoo-dev/
│
├── Dockerfile
├── docker-compose.yml
├── README.md
│
├── config/
│   └── odoo.conf
│
├── odoo/
│   ├── odoo-bin
│   ├── addons/
│   ├── odoo/
│   └── requirements.txt
│
├── custom_addons/
│   └── my_custom_module/
│       ├── __init__.py
│       └── __manifest__.py
│
└── enterprise/
    └── optional_enterprise_modules/

Folder Explanation

Folder/File Description
Dockerfile Builds the Odoo development image
docker-compose.yml Runs Odoo and PostgreSQL containers
config/odoo.conf Odoo configuration file
odoo/ Local Odoo core source code
custom_addons/ Your custom Odoo modules
enterprise/ Optional Odoo Enterprise addons
README.md Project documentation

Requirements

Install these tools before starting:

  • Docker
  • Docker Compose
  • Git
  • Code editor, for example VS Code or PyCharm

Check installation:

docker --version
docker compose version
git --version

Clone Odoo Source Code

Example for Odoo 17:

git clone https://github.com/odoo/odoo.git --branch 17.0 --depth 1 odoo

Example for Odoo 18:

git clone https://github.com/odoo/odoo.git --branch 18.0 --depth 1 odoo

Example for Odoo 16:

git clone https://github.com/odoo/odoo.git --branch 16.0 --depth 1 odoo

Make sure your Docker image version and Odoo source branch match.

Examples:

Docker image: odoo:17
Odoo source branch: 17.0
Docker image: odoo:18
Odoo source branch: 18.0
Docker image: odoo:16
Odoo source branch: 16.0

Create Custom Addons Folder

Create a folder for your custom modules:

mkdir custom_addons

Example custom addons structure:

custom_addons/
└── my_custom_module/
    ├── __init__.py
    └── __manifest__.py

Dockerfile

Create a file named:

Dockerfile

Use this content:

FROM odoo:17

USER root

RUN apt-get update && apt-get install -y \
    git \
    nano \
    vim \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /opt/odoo

USER odoo

CMD ["python3", "/opt/odoo/odoo-bin", "-c", "/etc/odoo/odoo.conf"]

If you are using Odoo 18, change:

FROM odoo:17

to:

FROM odoo:18

If you are using Odoo 16, change it to:

FROM odoo:16

docker-compose.yml

Create a file named:

docker-compose.yml

Use this content:

services:
  db:
    image: postgres:15
    container_name: odoo_db
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: odoo
      POSTGRES_PASSWORD: odoo
    volumes:
      - odoo-db-data:/var/lib/postgresql/data

  odoo:
    build: .
    container_name: odoo_app
    depends_on:
      - db
    ports:
      - "8069:8069"
    volumes:
      - ./odoo:/opt/odoo
      - ./custom_addons:/mnt/extra-addons
      - ./config/odoo.conf:/etc/odoo/odoo.conf
      - odoo-web-data:/var/lib/odoo
    command: python3 /opt/odoo/odoo-bin -c /etc/odoo/odoo.conf

volumes:
  odoo-db-data:
  odoo-web-data:

Odoo Configuration

Create the config folder:

mkdir config

Create the Odoo config file:

config/odoo.conf

Use this content:

[options]
admin_passwd = admin

db_host = db
db_port = 5432
db_user = odoo
db_password = odoo

addons_path = /opt/odoo/addons,/mnt/extra-addons

log_level = info

Using Odoo Enterprise

If you have Odoo Enterprise source code, place it in:

enterprise/

Update docker-compose.yml:

services:
  db:
    image: postgres:15
    container_name: odoo_db
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: odoo
      POSTGRES_PASSWORD: odoo
    volumes:
      - odoo-db-data:/var/lib/postgresql/data

  odoo:
    build: .
    container_name: odoo_app
    depends_on:
      - db
    ports:
      - "8069:8069"
    volumes:
      - ./odoo:/opt/odoo
      - ./enterprise:/mnt/enterprise
      - ./custom_addons:/mnt/extra-addons
      - ./config/odoo.conf:/etc/odoo/odoo.conf
      - odoo-web-data:/var/lib/odoo
    command: python3 /opt/odoo/odoo-bin -c /etc/odoo/odoo.conf

volumes:
  odoo-db-data:
  odoo-web-data:

Update config/odoo.conf:

[options]
admin_passwd = admin

db_host = db
db_port = 5432
db_user = odoo
db_password = odoo

addons_path = /opt/odoo/addons,/mnt/enterprise,/mnt/extra-addons

log_level = info

Recommended addons path order:

/opt/odoo/addons
/mnt/enterprise
/mnt/extra-addons

Start the Environment

Build and start containers:

docker compose up -d --build

Open Odoo in your browser:

http://localhost:8069

View Odoo logs:

docker compose logs -f odoo

Stop containers:

docker compose down

Stop containers and remove database volumes:

docker compose down -v

Be careful with:

docker compose down -v

It removes your PostgreSQL database data.


Access the Odoo Container

Enter the Odoo container:

docker compose exec odoo bash

Check mounted custom addons:

ls -la /mnt/extra-addons

Check Odoo config:

cat /etc/odoo/odoo.conf

Check local Odoo source:

ls -la /opt/odoo

Exit container:

exit

Access the PostgreSQL Container

Enter the PostgreSQL container:

docker compose exec db bash

Connect to PostgreSQL:

psql -U odoo -d postgres

List databases:

\l

Exit PostgreSQL:

\q

Exit container:

exit

Create a Custom Module

Create a sample custom module:

mkdir -p custom_addons/my_custom_module
touch custom_addons/my_custom_module/__init__.py
touch custom_addons/my_custom_module/__manifest__.py

Example structure:

custom_addons/my_custom_module/
├── __init__.py
└── __manifest__.py

Example __manifest__.py:

{
    "name": "My Custom Module",
    "version": "17.0.1.0.0",
    "category": "Custom",
    "summary": "My first custom Odoo module",
    "description": """
        This is a sample custom module for Odoo development.
    """,
    "author": "Your Name",
    "website": "https://example.com",
    "depends": ["base"],
    "data": [],
    "installable": True,
    "application": False,
    "license": "LGPL-3",
}

Restart Odoo:

docker compose restart odoo

Then in Odoo:

Settings → Activate Developer Mode
Apps → Update Apps List

Search for:

My Custom Module

Important:

Remove the default Apps filter from the search bar if your module does not appear.


Example Custom Model Module

Create this structure:

custom_addons/my_custom_module/
├── __init__.py
├── __manifest__.py
├── models/
│   ├── __init__.py
│   └── custom_model.py
└── views/
    └── custom_model_views.xml

Create folders:

mkdir -p custom_addons/my_custom_module/models
mkdir -p custom_addons/my_custom_module/views
touch custom_addons/my_custom_module/models/__init__.py

Update root __init__.py:

from . import models

Update models/__init__.py:

from . import custom_model

Create models/custom_model.py:

from odoo import models, fields


class CustomModel(models.Model):
    _name = "custom.model"
    _description = "Custom Model"

    name = fields.Char(string="Name", required=True)
    description = fields.Text(string="Description")
    active = fields.Boolean(string="Active", default=True)

Create views/custom_model_views.xml:

<odoo>
    <record id="view_custom_model_tree" model="ir.ui.view">
        <field name="name">custom.model.tree</field>
        <field name="model">custom.model</field>
        <field name="arch" type="xml">
            <tree>
                <field name="name"/>
                <field name="description"/>
                <field name="active"/>
            </tree>
        </field>
    </record>

    <record id="view_custom_model_form" model="ir.ui.view">
        <field name="name">custom.model.form</field>
        <field name="model">custom.model</field>
        <field name="arch" type="xml">
            <form>
                <sheet>
                    <group>
                        <field name="name"/>
                        <field name="description"/>
                        <field name="active"/>
                    </group>
                </sheet>
            </form>
        </field>
    </record>

    <record id="action_custom_model" model="ir.actions.act_window">
        <field name="name">Custom Models</field>
        <field name="res_model">custom.model</field>
        <field name="view_mode">tree,form</field>
    </record>

    <menuitem id="menu_custom_root"
              name="Custom App"
              sequence="10"/>

    <menuitem id="menu_custom_model"
              name="Custom Models"
              parent="menu_custom_root"
              action="action_custom_model"
              sequence="10"/>
</odoo>

Update __manifest__.py:

{
    "name": "My Custom Module",
    "version": "17.0.1.0.0",
    "category": "Custom",
    "summary": "My first custom Odoo module",
    "author": "Your Name",
    "depends": ["base"],
    "data": [
        "views/custom_model_views.xml",
    ],
    "installable": True,
    "application": True,
    "license": "LGPL-3",
}

Upgrade the module:

docker compose exec odoo python3 /opt/odoo/odoo-bin \
    -c /etc/odoo/odoo.conf \
    -d your_database_name \
    -u my_custom_module \
    --stop-after-init

Restart Odoo:

docker compose restart odoo

Git Setup

Recommended Git structure:

odoo-dev/
├── odoo/              # Odoo core repository
├── custom_addons/     # Your custom addons repository
├── enterprise/        # Optional Enterprise repository
├── Dockerfile
├── docker-compose.yml
└── config/

Odoo Core Remote

Check the remote:

cd odoo
git remote -v

Example result:

origin https://github.com/odoo/odoo.git

Custom Addons Remote

Initialize Git inside custom_addons:

cd custom_addons
git init
git add .
git commit -m "Initial custom addons"
git branch -M main
git remote add origin git@github.com:yourname/odoo-custom-addons.git
git push -u origin main

This keeps Odoo core and your custom modules separate.

Do not put your custom modules inside:

odoo/addons/

Recommended:

custom_addons/

Addons Path

The addons_path tells Odoo where to find modules.

Example without Enterprise:

addons_path = /opt/odoo/addons,/mnt/extra-addons

Example with Enterprise:

addons_path = /opt/odoo/addons,/mnt/enterprise,/mnt/extra-addons

Make sure the paths match your Docker volume mounts.

Example:

volumes:
  - ./custom_addons:/mnt/extra-addons

Then odoo.conf must include:

/mnt/extra-addons

If your compose file has:

- ./custom_addons:/mnt/custom-addons

Then your config must use:

/mnt/custom-addons

The names must match exactly.


Common Commands

Start Containers

docker compose up -d

Build and Start Containers

docker compose up -d --build

Stop Containers

docker compose down

Stop Containers and Delete Volumes

docker compose down -v

Restart Odoo

docker compose restart odoo

View Odoo Logs

docker compose logs -f odoo

View Database Logs

docker compose logs -f db

Enter Odoo Container

docker compose exec odoo bash

Enter PostgreSQL Container

docker compose exec db bash

Check Mounted Custom Addons

docker compose exec odoo ls -la /mnt/extra-addons

Check Odoo Config

docker compose exec odoo cat /etc/odoo/odoo.conf

Upgrade a Module

Replace your_database_name and your_module_name:

docker compose exec odoo python3 /opt/odoo/odoo-bin \
    -c /etc/odoo/odoo.conf \
    -d your_database_name \
    -u your_module_name \
    --stop-after-init

Then restart:

docker compose restart odoo

Install a Module from Command Line

Replace your_database_name and your_module_name:

docker compose exec odoo python3 /opt/odoo/odoo-bin \
    -c /etc/odoo/odoo.conf \
    -d your_database_name \
    -i your_module_name \
    --stop-after-init

Then restart:

docker compose restart odoo

Database Management

List Databases

docker compose exec db psql -U odoo -d postgres -c "\l"

Backup Database

Replace your_database_name:

docker compose exec db pg_dump -U odoo your_database_name > backup.sql

Restore Database

Create database first if needed:

docker compose exec db createdb -U odoo restored_database

Restore:

cat backup.sql | docker compose exec -T db psql -U odoo restored_database

Development Workflow

Recommended workflow:

1. Start Docker containers

docker compose up -d

2. Create or edit modules in custom addons

custom_addons/

3. Restart Odoo if Python files changed

docker compose restart odoo

4. Update Apps List in Odoo

In the Odoo web interface:

Settings → Activate Developer Mode
Apps → Update Apps List

5. Upgrade your module

docker compose exec odoo python3 /opt/odoo/odoo-bin \
    -c /etc/odoo/odoo.conf \
    -d your_database_name \
    -u your_module_name \
    --stop-after-init

6. Restart Odoo again

docker compose restart odoo

Updating Apps List

In Odoo UI:

Settings → Activate Developer Mode
Apps → Update Apps List

Then search your module.

Important:

Remove the default search filter:

Apps

Sometimes custom technical modules do not appear because the default Apps filter is active.


Troubleshooting


Problem: /mnt/extra-addons is not shown

Check the volume mount in docker-compose.yml:

volumes:
  - ./custom_addons:/mnt/extra-addons

Check inside the container:

docker compose exec odoo ls -la /mnt/extra-addons

If it is empty, check that your local custom_addons folder contains modules.


Problem: Custom module does not appear in Apps

Check these items.

1. Is the folder mounted?

docker compose exec odoo ls -la /mnt/extra-addons

2. Is the path in odoo.conf?

docker compose exec odoo cat /etc/odoo/odoo.conf

Expected:

addons_path = /opt/odoo/addons,/mnt/extra-addons

3. Does the module have __manifest__.py?

Valid:

custom_addons/my_module/__manifest__.py

Invalid:

custom_addons/my_module/something_else/__manifest__.py

unless your addons_path points to the correct parent folder.

4. Is the module installable?

In __manifest__.py:

"installable": True

5. Did you update Apps List?

In Odoo:

Apps → Update Apps List

6. Did you remove the default Apps filter?

In the Apps search bar, remove:

Apps

7. Check logs

docker compose logs -f odoo

Problem: Docker build fails on pip3 install

If you use the official Odoo Docker image, do not reinstall the full Odoo core requirements.txt.

Avoid this:

COPY ./odoo/requirements.txt /tmp/requirements.txt
RUN pip3 install --break-system-packages -r /tmp/requirements.txt

Usually, this Dockerfile is enough:

FROM odoo:17

USER root

RUN apt-get update && apt-get install -y \
    git \
    nano \
    vim \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /opt/odoo

USER odoo

CMD ["python3", "/opt/odoo/odoo-bin", "-c", "/etc/odoo/odoo.conf"]

If your custom modules need extra Python packages, create:

requirements-extra.txt

Example:

requests
openpyxl
boto3

Then update Dockerfile:

FROM odoo:17

USER root

RUN apt-get update && apt-get install -y \
    git \
    nano \
    vim \
    python3-pip \
    && rm -rf /var/lib/apt/lists/*

COPY ./requirements-extra.txt /tmp/requirements-extra.txt

RUN pip3 install --break-system-packages --no-cache-dir -r /tmp/requirements-extra.txt

WORKDIR /opt/odoo

USER odoo

CMD ["python3", "/opt/odoo/odoo-bin", "-c", "/etc/odoo/odoo.conf"]

Problem: Odoo image version and source version mismatch

Make sure these match:

FROM odoo:17

with:

Odoo source branch 17.0

Check branch:

cd odoo
git branch

Switch branch:

git checkout 17.0

For Odoo 18:

FROM odoo:18

Use branch:

git checkout 18.0

Problem: Database connection error

Check config/odoo.conf:

db_host = db
db_port = 5432
db_user = odoo
db_password = odoo

Check docker-compose.yml:

db:
  environment:
    POSTGRES_USER: odoo
    POSTGRES_PASSWORD: odoo

The database user and password must match.


Problem: Permission issue in custom addons

Check file permissions:

ls -la custom_addons

On Linux or macOS, you may fix ownership with:

sudo chown -R $USER:$USER custom_addons

Then restart:

docker compose restart odoo

Problem: Changes in Python files are not applied

Restart Odoo:

docker compose restart odoo

Then upgrade the module:

docker compose exec odoo python3 /opt/odoo/odoo-bin \
    -c /etc/odoo/odoo.conf \
    -d your_database_name \
    -u your_module_name \
    --stop-after-init

Restart again:

docker compose restart odoo

Problem: XML view changes are not applied

Upgrade your module:

docker compose exec odoo python3 /opt/odoo/odoo-bin \
    -c /etc/odoo/odoo.conf \
    -d your_database_name \
    -u your_module_name \
    --stop-after-init

Then restart:

docker compose restart odoo

Keep Odoo Core Clean

Do not modify Odoo core unless absolutely necessary.

Avoid editing files inside:

odoo/addons/
odoo/odoo/

Instead, create custom modules inside:

custom_addons/

Use inheritance instead of changing core files.

Example:

from odoo import models, fields


class SaleOrder(models.Model):
    _inherit = "sale.order"

    x_custom_note = fields.Char(string="Custom Note")

Use Separate Git Repositories

Recommended:

odoo/              → Odoo official source code
custom_addons/     → Your custom addons repository
enterprise/        → Odoo Enterprise source code, optional

This makes upgrades and maintenance easier.


Use Version-Specific Folders

Example:

odoo16-dev/
odoo17-dev/
odoo18-dev/

Each project can have its own:

Dockerfile
docker-compose.yml
odoo.conf
custom_addons
database volume

Use Meaningful Module Names

Good module names:

sale_order_customization
stock_barcode_extension
school_management
account_report_custom

Avoid unclear names:

test
module1
custom
new_module

Use Git Frequently

Inside custom_addons:

git status
git add .
git commit -m "Add sale order customization"
git push

Full Example Final Files

Dockerfile

FROM odoo:17

USER root

RUN apt-get update && apt-get install -y \
    git \
    nano \
    vim \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /opt/odoo

USER odoo

CMD ["python3", "/opt/odoo/odoo-bin", "-c", "/etc/odoo/odoo.conf"]

docker-compose.yml

services:
  db:
    image: postgres:15
    container_name: odoo_db
    environment:
      POSTGRES_DB: postgres
      POSTGRES_USER: odoo
      POSTGRES_PASSWORD: odoo
    volumes:
      - odoo-db-data:/var/lib/postgresql/data

  odoo:
    build: .
    container_name: odoo_app
    depends_on:
      - db
    ports:
      - "8069:8069"
    volumes:
      - ./odoo:/opt/odoo
      - ./custom_addons:/mnt/extra-addons
      - ./config/odoo.conf:/etc/odoo/odoo.conf
      - odoo-web-data:/var/lib/odoo
    command: python3 /opt/odoo/odoo-bin -c /etc/odoo/odoo.conf

volumes:
  odoo-db-data:
  odoo-web-data:

config/odoo.conf

[options]
admin_passwd = admin

db_host = db
db_port = 5432
db_user = odoo
db_password = odoo

addons_path = /opt/odoo/addons,/mnt/extra-addons

log_level = info

Final Notes

This setup runs Odoo from your local source code inside Docker.

Local Odoo source:

./odoo → /opt/odoo

Custom addons:

./custom_addons → /mnt/extra-addons

Odoo detects custom modules using:

addons_path = /opt/odoo/addons,/mnt/extra-addons

After creating or modifying modules:

docker compose restart odoo

Then update the Apps List from the Odoo interface.

For normal Odoo development, always prefer custom addons over editing Odoo core directly.