Odoo's modular architecture makes it one of the most flexible ERP systems available. While the standard installation includes core modules, Odoo's real power comes from thousands of community and commercial modules. This guide covers professional module management: using command-line tools and git version control for installation, updates, and maintenance.
Why Choose CLI and Git Over Web Interface
Installing modules through Odoo's web interface is straightforward — upload a ZIP file, click install, done. However, this approach has significant limitations for professional deployments:
No Version Control. You lose track of which module versions are installed, when updates occurred, and what changed between versions.
Manual Update Process. Each module requires individual manual updates through the interface. With dozens of modules, this becomes hours of repetitive work.
Dependency Hell. Modules often depend on other modules. Manual dependency tracking and installation through the GUI quickly becomes unmanageable.
Zero Automation. You cannot automate module installation in CI/CD pipelines, Docker containers, or when provisioning new instances.
No Change History. When a module breaks your system, rolling back to a previous working version is nearly impossible.
Professional deployment requires git for module management and CLI for installation. This approach provides complete control, reproducibility, and automation capabilities that scale with your organization.
Understanding Odoo Module Architecture
Before installing modules, understanding Odoo's module structure is essential.
Directory Structure
Odoo searches for modules in directories specified in the addons_path configuration parameter. Standard structure:
/opt/odoo/
├── odoo/ # Core Odoo codebase
│ └── addons/ # Built-in modules
├── addons/ # Official Enterprise modules
└── custom-addons/ # Your custom modules
├── module1/
├── module2/
└── module3/
Each module is a directory with specific structure:
module_name/
├── __init__.py # Python package initialization
├── __manifest__.py # Module metadata
├── models/ # Data models
│ ├── __init__.py
│ └── model_name.py
├── views/ # XML views
│ └── view_name.xml
├── security/ # Access rights
│ ├── ir.model.access.csv
│ └── security.xml
├── data/ # Data to load
│ └── data.xml
├── static/ # Static files (CSS, JS, images)
│ ├── description/
│ │ └── icon.png
│ └── src/
└── i18n/ # Translations
├── es.po
└── fr.po
Manifest File
Every module requires a __manifest__.py file containing metadаta:
{
'name': 'Module Name',
'version': '16.0.1.0.0',
'category': 'Sales',
'summary': 'Short description',
'description': 'Detailed description',
'author': 'Author Name',
'website': 'https://example.com',
'license': 'LGPL-3',
'depends': ['base', 'sale'],
'data': [
'security/ir.model.access.csv',
'views/view_name.xml',
],
'demo': [
'demo/demo_data.xml',
],
'installable': True,
'application': False,
'auto_install': False,
}
The depends parameter is critical — it specifies module dependencies. Odoo automatically installs dependent modules.
Environment Preparation
Before installing modules, prepare your system properly.
Verify Odoo Installation
Check Odoo service status:
sudo systemctl status odoo
Verify Odoo version:
odoo --version
Alternative Python check:
python3 -c "import odoo; print(odoo.release.version)"
Identify Addons Paths
Locate Odoo configuration file:
sudo find / -name odoo.conf 2>/dev/null
Common locations:
/etc/odoo/odoo.conf/etc/odoo.conf~/.odoorc
Check current addons paths:
grep addons_path /etc/odoo/odoo.conf
Create Custom Addons Directory
Create dedicated directory for third-party modules:
sudo mkdir -p /opt/odoo/custom-addons
Set proper ownership:
sudo chown -R odoo:odoo /opt/odoo/custom-addons
Add directory to configuration:
sudo nano /etc/odoo/odoo.conf
Find or add the addons_path line:
addons_path = /opt/odoo/odoo/addons,/opt/odoo/addons,/opt/odoo/custom-addons
Order matters — Odoo checks directories left to right. If modules with identical names exist in multiple directories, the first found is used.
Installing Modules via Git Clone
Git is the primary method for installing community modules. Most modules are hosted on GitHub or GitLab.
Finding Modules
Primary Odoo module sources:
Odoo Community Association (OCA):
- Repository: https://github.com/OCA
- High code quality
- Regular updates
- Strict code review process
GitHub:
- Search: https://github.com/search?q=odoo+module
- Vast module selection
- Varying quality levels
Odoo Apps Store:
- https://apps.odoo.com
- Official marketplace
- Paid and free modules
Cloning Single Module
Navigate to custom addons directory:
cd /opt/odoo/custom-addons
Clone module repository:
git clone https://github.com/OCA/sale-workflow.git
This creates a sale-workflow directory containing all repository modules.
Cloning Specific Version
Odoo modules are version-specific. For Odoo 16.0, use the 16.0 branch:
git clone -b 16.0 https://github.com/OCA/sale-workflow.git
Check available branches before cloning:
git ls-remote --heads https://github.com/OCA/sale-workflow.git
Cloning Multiple Repositories
Create script for batch module installation:
nano /opt/odoo/install-modules.sh
Script content:
#!/bin/bash
ADDONS_DIR="/opt/odoo/custom-addons"
BRANCH="16.0"
cd $ADDONS_DIR
repos=(
"https://github.com/OCA/sale-workflow.git"
"https://github.com/OCA/account-financial-tools.git"
"https://github.com/OCA/project.git"
"https://github.com/OCA/stock-logistics-warehouse.git"
)
for repo in "${repos[@]}"; do
repo_name=$(basename $repo .git)
if [ -d "$repo_name" ]; then
echo "Updating $repo_name..."
cd $repo_name
git pull origin $BRANCH
cd ..
else
echo "Cloning $repo_name..."
git clone -b $BRANCH $repo
fi
done
sudo chown -R odoo:odoo $ADDONS_DIR
echo "Installation completed"
Make script executable:
chmod +x /opt/odoo/install-modules.sh
Run installation:
sudo /opt/odoo/install-modules.sh
Cloning Specific Commit
Sometimes a specific module version is needed rather than latest:
git clone -b 16.0 https://github.com/OCA/sale-workflow.git
cd sale-workflow
git checkout abc123def456
Clone with limited history depth:
git clone --depth 1 -b 16.0 https://github.com/OCA/sale-workflow.git
The --depth 1 flag downloads only the latest commit without history, saving time and space.
Working with Submodule Repositories
Many Odoo projects use git submodules for dependency management.
Adding Modules as Submodules
Initialize git repository for your project:
cd /opt/odoo
git init
Add modules as submodules:
git submodule add -b 16.0 https://github.com/OCA/sale-workflow.git custom-addons/sale-workflow
Commit changes:
git add .gitmodules custom-addons/sale-workflow
git commit -m "Add sale-workflow module"
Cloning Projects with Submodules
When cloning projects with submodules:
git clone https://github.com/yourcompany/odoo-project.git
cd odoo-project
Initialize and update submodules:
git submodule init
git submodule update
Clone with submodules directly:
git clone --recurse-submodules https://github.com/yourcompany/odoo-project.git
Updating Submodules
Update all submodules to latest versions in their branches:
git submodule update --remote --merge
Update specific submodule:
git submodule update --remote custom-addons/sale-workflow
Installing Python Dependencies
Many modules require additional Python libraries.
Finding requirements.txt
Check for requirements.txt files in modules:
find /opt/odoo/custom-addons -name requirements.txt
Installing Dependencies
Install dependencies for specific module:
pip3 install -r /opt/odoo/custom-addons/sale-workflow/requirements.txt
With system packages flag:
sudo pip3 install --break-system-packages -r /opt/odoo/custom-addons/sale-workflow/requirements.txt
Creating Unified requirements.txt
Combine all requirements.txt from installed modules:
find /opt/odoo/custom-addons -name requirements.txt -exec cat {} \; | sort | uniq > /opt/odoo/all-requirements.txt
Install all dependencies at once:
pip3 install -r /opt/odoo/all-requirements.txt
Using Virtual Environment
Create virtual environment for dependency isolation:
python3 -m venv /opt/odoo/venv
Activate environment:
source /opt/odoo/venv/bin/activate
Install dependencies in environment:
pip install -r /opt/odoo/all-requirements.txt
Activating Modules via Command Line
After installing module files, activate them in Odoo.
Update Module List
Odoo scans addons directories at startup but doesn't automatically detect new modules. Update list:
odoo -d your_database -u base --stop-after-init
Command parameters:
-d your_database— database name-u base— update base module (triggers rescan)--stop-after-init— stop after initialization
Install Module via CLI
Install module in database:
odoo -d your_database -i module_name --stop-after-init
Install multiple modules simultaneously:
odoo -d your_database -i module1,module2,module3 --stop-after-init
Update Installed Module
After modifying module code, update it:
odoo -d your_database -u module_name --stop-after-init
Update all installed modules:
odoo -d your_database -u all --stop-after-init
Using odoo-bin
If Odoo installed from source:
cd /opt/odoo/odoo
./odoo-bin -d your_database -i module_name --stop-after-init
With configuration file:
./odoo-bin -c /etc/odoo/odoo.conf -d your_database -i module_name --stop-after-init
Installation Without Stopping Service
For production servers, use --no-http flag:
odoo -d your_database -i module_name --no-http
Odoo performs installation in background without starting web server.
Working with Odoo Shell
Odoo Shell is an interactive Python console for data operations.
Starting Odoo Shell
Launch shell for specific database:
odoo shell -d your_database
With configuration file:
odoo shell -c /etc/odoo/odoo.conf -d your_database
Installing Module via Shell
Install module programmatically:
env['ir.module.module'].search([('name', '=', 'sale_management')]).button_immediate_install()
Install multiple modules:
modules = env['ir.module.module'].search([('name', 'in', ['sale_management', 'purchase'])])
modules.button_immediate_install()
Checking Module Status
Check installed modules:
installed = env['ir.module.module'].search([('state', '=', 'installed')])
for module in installed:
print(f"{module.name}: {module.latest_version}")
Find modules requiring updates:
to_upgrade = env['ir.module.module'].search([('state', '=', 'to upgrade')])
for module in to_upgrade:
print(module.name)
Updating Module via Shell
Update module programmatically:
module = env['ir.module.module'].search([('name', '=', 'sale_management')])
module.button_immediate_upgrade()
API Automation
For complete automation, use Odoo's XML-RPC API.
Connecting to API
Create Python script for connection:
import xmlrpc.client
url = 'http://localhost:8069'
db = 'your_database'
username = 'admin'
password = 'admin'
common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common')
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object')
Installing Module via API
Find module by name:
module_id = models.execute_kw(db, uid, password,
'ir.module.module', 'search',
[[('name', '=', 'sale_management')]])
Install module:
models.execute_kw(db, uid, password,
'ir.module.module', 'button_immediate_install',
[module_id])
Batch Installation via API
Install module list:
module_names = ['sale_management', 'purchase', 'stock']
for name in module_names:
module_id = models.execute_kw(db, uid, password,
'ir.module.module', 'search',
[[('name', '=', name)]])
if module_id:
models.execute_kw(db, uid, password,
'ir.module.module', 'button_immediate_install',
[module_id])
print(f"Installed: {name}")
Managing Module Versions
Version control is critical for system stability.
Creating versions.txt File
Record versions of all installed modules:
cd /opt/odoo/custom-addons
find . -maxdepth 2 -name __manifest__.py -exec grep -H "version" {} \; > versions.txt
Use git for tracking:
cd /opt/odoo/custom-addons/sale-workflow
git log -1 --format="%H" > VERSION
Creating Version Tags
Create git tag after successful update:
cd /opt/odoo/custom-addons/sale-workflow
git tag -a v1.0.0 -m "Stable version for production"
git push origin v1.0.0
Rolling Back to Previous Version
If module update causes issues:
cd /opt/odoo/custom-addons/sale-workflow
git log --oneline
git checkout <commit-hash>
Then update module in Odoo:
odoo -d your_database -u sale_workflow --stop-after-init
Pinning Versions via Requirements
For Python modules, use exact versions:
pip freeze > /opt/odoo/requirements-frozen.txt
Use this file during deployment:
pip install -r /opt/odoo/requirements-frozen.txt
Working with Private Repositories
Company modules often reside in private repositories.
Configuring SSH Keys
Generate SSH key for odoo user:
sudo -u odoo ssh-keygen -t rsa -b 4096 -C "odoo@yourserver"
Copy public key:
sudo cat /home/odoo/.ssh/id_rsa.pub
Add key to Git server settings (GitHub, GitLab, Bitbucket).
Cloning Private Repository
Use SSH URL instead of HTTPS:
cd /opt/odoo/custom-addons
sudo -u odoo git clone git@github.com:yourcompany/private-modules.git
Using Access Tokens
For HTTPS, use personal access token:
git clone https://YOUR_TOKEN@github.com/yourcompany/private-modules.git
Configure credential helper:
git config --global credential.helper store
Token saves after first clone.
HTTPS Clone with Authentication
Use URL with credentials:
git clone https://username:token@gitlab.com/yourcompany/private-modules.git
For security, use environment variables:
GIT_USER="username"
GIT_TOKEN="your_token"
git clone https://${GIT_USER}:${GIT_TOKEN}@gitlab.com/yourcompany/private-modules.git
Structuring Custom Modules
Organize modules for easy management.
Categorization
Create category-based directory structure:
mkdir -p /opt/odoo/custom-addons/{oca,proprietary,custom,community}
Place modules by category:
oca/— OCA modulesproprietary/— proprietary modulescustom/— internally developed modulescommunity/— community modules
Update configuration:
addons_path = /opt/odoo/odoo/addons,/opt/odoo/custom-addons/oca,/opt/odoo/custom-addons/proprietary,/opt/odoo/custom-addons/custom,/opt/odoo/custom-addons/community
Using Symbolic Links
Create symbolic links to individual modules:
cd /opt/odoo/custom-addons
ln -s /opt/odoo/sources/sale-workflow/sale_order_priority ./
Useful when repository contains many modules but only some are needed.
Organization via requirements-repos.txt
Create file with repository list:
# OCA modules
https://github.com/OCA/sale-workflow.git@16.0
https://github.com/OCA/account-financial-tools.git@16.0
# Custom modules
git@github.com:yourcompany/custom-modules.git@main
Write script for automatic installation:
#!/bin/bash
while IFS= read -r line; do
[[ "$line" =~ ^#.*$ ]] && continue
[[ -z "$line" ]] && continue
repo=$(echo $line | cut -d@ -f1)
branch=$(echo $line | cut -d@ -f2)
name=$(basename $repo .git)
cd /opt/odoo/custom-addons
if [ -d "$name" ]; then
cd $name
git pull origin $branch
else
git clone -b $branch $repo
fi
done < requirements-repos.txt
Updating Modules
Regular module updates are critical for security and bug fixes.
Updating via Git Pull
Update module to latest version in branch:
cd /opt/odoo/custom-addons/sale-workflow
git pull origin 16.0
Batch Update All Modules
Update all git repositories in directory:
find /opt/odoo/custom-addons -type d -name .git -exec sh -c 'cd "{}" && cd .. && git pull' \;
More readable script:
#!/bin/bash
for dir in /opt/odoo/custom-addons/*/; do
if [ -d "$dir/.git" ]; then
echo "Updating $(basename $dir)..."
cd "$dir"
git pull
fi
done
Checking Updates Before Applying
Check available updates without applying:
cd /opt/odoo/custom-addons/sale-workflow
git fetch origin
git log HEAD..origin/16.0 --oneline
Updating Modules in Odoo After Git Pull
After updating module files, update in database:
odoo -d your_database -u sale_workflow --stop-after-init
Update all changed modules:
odoo -d your_database -u all --stop-after-init
Testing Modules
Test modules before production installation.
Creating Test Database
Create copy of production database for testing:
createdb -T production_db test_db
Via psql:
psql -c "CREATE DATABASE test_db WITH TEMPLATE production_db OWNER odoo;"
Installing Module in Test Database
Install module only in test database:
odoo -d test_db -i new_module --stop-after-init
Running Automated Tests
Run module tests:
odoo -d test_db -i new_module --test-enable --stop-after-init
Run tests without installation:
odoo -d test_db --test-enable --test-tags new_module --stop-after-init
Checking Dependencies
Verify all dependencies installed:
odoo -d test_db -i new_module --test-enable --stop-after-init 2>&1 | grep -i "error\|warning"
Removing Modules
Sometimes complete module removal is necessary.
Uninstallation via CLI
Uninstall module from database:
odoo shell -d your_database
Execute in shell:
module = env['ir.module.module'].search([('name', '=', 'module_name')])
module.button_immediate_uninstall()
Removing Module Files
After uninstallation, remove files:
rm -rf /opt/odoo/custom-addons/module_name
If module installed via git:
cd /opt/odoo/custom-addons
git rm -r module_name
git commit -m "Remove module_name"
Database Cleanup
Some modules leave data after removal. Clean manually:
env.cr.execute("DELETE FROM ir_model_data WHERE module='module_name'")
env.cr.execute("DELETE FROM ir_model WHERE model LIKE 'module_name.%'")
env.cr.commit()
Migrating Modules Between Odoo Versions
When upgrading Odoo, modules require migration.
Checking Compatibility
Check if module version exists for new Odoo version:
cd /opt/odoo/custom-addons/sale-workflow
git branch -r | grep 17.0
Switching to New Version
Switch to new version branch:
git checkout 17.0
Updating After Migration
After Odoo upgrade, update all modules:
odoo -d your_database -u all --stop-after-init
Creating Migration Script
Automate migration:
#!/bin/bash
OLD_VERSION="16.0"
NEW_VERSION="17.0"
ADDONS_DIR="/opt/odoo/custom-addons"
cd $ADDONS_DIR
for dir in */; do
if [ -d "$dir/.git" ]; then
cd "$dir"
if git branch -r | grep -q "$NEW_VERSION"; then
echo "Migrating $dir to $NEW_VERSION..."
git fetch origin
git checkout $NEW_VERSION
git pull origin $NEW_VERSION
else
echo "Version $NEW_VERSION unavailable for $dir"
fi
cd ..
fi
done
Troubleshooting Common Issues
Problem: Module Not Appearing in List
Cause: Odoo hasn't scanned directory or path not in addons_path.
Solution:
Check configuration:
grep addons_path /etc/odoo/odoo.conf
Check permissions:
ls -la /opt/odoo/custom-addons/module_name
Update module list:
odoo -d your_database -u base --stop-after-init
Problem: Error "No module named 'module_dependency'"
Cause: Module Python dependencies not installed.
Solution:
Find requirements.txt:
find /opt/odoo/custom-addons/module_name -name requirements.txt
Install dependencies:
pip3 install -r /opt/odoo/custom-addons/module_name/requirements.txt
Problem: Module Installed But Not Working
Cause: Dependencies not updated or version conflict.
Solution:
Check Odoo logs:
tail -f /var/log/odoo/odoo-server.log
Force module update:
odoo -d your_database -u module_name --stop-after-init
Check dependencies in manifest.py:
cat /opt/odoo/custom-addons/module_name/__manifest__.py | grep depends
Problem: Git Authentication Failed
Cause: SSH keys or access tokens incorrectly configured.
Solution:
Test SSH connection:
ssh -T git@github.com
Check git settings:
git config --global --list
Use SSH instead of HTTPS:
git remote set-url origin git@github.com:username/repo.git
Problem: Module Version Conflicts
Cause: Incompatible dependency versions installed.
Solution:
Check all module versions:
odoo shell -d your_database
Execute in shell:
modules = env['ir.module.module'].search([('state', '=', 'installed')])
for m in modules:
print(f"{m.name}: {m.latest_version}")
Roll back problematic module:
cd /opt/odoo/custom-addons/module_name
git log --oneline
git checkout <previous-commit>
CI/CD Automation
Integrate module installation into deployment pipeline.
GitLab CI Example
Create .gitlab-ci.yml:
stages:
- test
- deploy
test_modules:
stage: test
script:
- cd /opt/odoo/custom-addons
- git pull
- pip3 install -r requirements.txt
- odoo -d test_db -i module_name --test-enable --stop-after-init
deploy_production:
stage: deploy
script:
- cd /opt/odoo/custom-addons
- git pull origin main
- pip3 install -r requirements.txt
- odoo -d production_db -u module_name --stop-after-init
- systemctl restart odoo
only:
- main
GitHub Actions Example
Create .github/workflows/deploy.yml:
name: Deploy Odoo Modules
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup SSH
uses: webfactory/ssh-agent@v0.5.3
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Deploy to server
run: |
ssh user@server "cd /opt/odoo/custom-addons && git pull"
ssh user@server "pip3 install -r /opt/odoo/custom-addons/requirements.txt"
ssh user@server "odoo -d production_db -u all --stop-after-init"
ssh user@server "systemctl restart odoo"
Docker Integration
Create Dockerfile for Odoo with custom modules:
FROM odoo:16.0
USER root
COPY custom-addons /opt/odoo/custom-addons
RUN pip3 install -r /opt/odoo/custom-addons/requirements.txt
RUN chown -R odoo:odoo /opt/odoo/custom-addons
USER odoo
Build image:
docker build -t mycompany/odoo:16.0 .
Module Monitoring
Track module state in production.
Checking Installed Modules
Get list of installed modules:
odoo shell -d your_database
Execute:
installed = env['ir.module.module'].search([('state', '=', 'installed')])
for m in installed:
print(f"{m.name} - {m.latest_version}")
Creating Module Report
Create script for report generation:
#!/usr/bin/env python3
import xmlrpc.client
url = 'http://localhost:8069'
db = 'your_database'
username = 'admin'
password = 'admin'
common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common')
uid = common.authenticate(db, username, password, {})
models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object')
modules = models.execute_kw(db, uid, password,
'ir.module.module', 'search_read',
[[('state', '=', 'installed')]],
{'fields': ['name', 'latest_version', 'author']})
print("Installed modules:")
for m in modules:
print(f"- {m['name']}: {m['latest_version']} (by {m['author']})")
Setting Up Alerts
Configure critical module monitoring:
#!/bin/bash
CRITICAL_MODULES=("sale_management" "account" "stock")
DB="your_database"
for module in "${CRITICAL_MODULES[@]}"; do
status=$(odoo shell -d $DB -c "env['ir.module.module'].search([('name','=','$module')]).state")
if [ "$status" != "installed" ]; then
echo "ALERT: Module $module is not installed!"
fi
done
Conclusion
Professional Odoo module management via command line and git provides complete system control. Key advantages of this approach:
Reproducibility. You know exactly which module versions are installed and can recreate environment on any server.
Automation. Module installation and updates fully automate through scripts and CI/CD.
Version Control. Git enables change tracking, rollback to previous versions, and branch management.
Team Collaboration. Multiple developers work with modules using standard git tools.
Security. Easy module change auditing and code source tracking.
Essential commands for daily work:
Clone modules:
git clone -b 16.0 https://github.com/OCA/sale-workflow.git
Update modules:
cd /opt/odoo/custom-addons/sale-workflow && git pull
Install in Odoo:
odoo -d your_database -i module_name --stop-after-init
Update module:
odoo -d your_database -u module_name --stop-after-init
Follow these practices, and Odoo module management becomes a straightforward, predictable process.