Odoo CI/CD and Staging: Complete Guide
Master Odoo development workflows with staging environments, CI/CD pipelines, and automated testing. Learn Git branching strategies, GitHub Actions, GitLab CI, and deployment best practices.
Why Development Workflows Matter for Odoo
Professional Odoo development requires more than just writing code. Without proper development workflows, teams face broken deployments, lost work, and frustrated users. A well-designed CI/CD pipeline with staging environments transforms chaotic development into reliable, repeatable releases. Whether you're deploying Odoo for the first time or scaling an existing system, proper DevOps practices are essential for development teams.
Reduced Risk
Test changes in staging before production. Catch bugs before they affect real users and business operations.
Team Collaboration
Multiple developers can work simultaneously without conflicts. Code reviews ensure quality before merging.
Fast Rollbacks
When issues occur, quickly revert to the previous working version. Minimize downtime and user impact.
Odoo Development Workflow Overview
+-------------+ +-------------+ +-------------+ +-------------+
| LOCAL | | FEATURE | | STAGING | | PRODUCTION |
| DEV | --> | BRANCH | --> | ENVIRONMENT | --> | ENVIRONMENT |
+-------------+ +-------------+ +-------------+ +-------------+
| | | |
v v v v
Developer Git Push Auto Deploy Manual Deploy
writes code triggers CI to staging after approval
| | |
v v v
Run Tests QA Testing Live Users
Lint Code Client Review Business Data
Build Check Integration Test
CI/CD PIPELINE FLOW
+-----------------------------------------------------------------------+
| Commit --> Lint --> Unit Tests --> Build --> Deploy Staging --> QA |
| | |
| Approval --> Deploy Production |
+-----------------------------------------------------------------------+
Development Environment Setup
A consistent local development environment is the foundation of a good workflow. Every developer should have the same setup to avoid environment-specific bugs.
Docker for Local Development
Docker provides the most consistent development experience. Every developer gets the same Odoo version, Python version, and dependencies. For production-ready Docker configurations, see our complete Odoo Docker deployment guide.
version: '3.8'
services:
odoo:
image: odoo:17.0
container_name: odoo-dev
depends_on:
- db
ports:
- "8069:8069"
- "8072:8072"
volumes:
# Mount your custom addons for live development
- ./addons:/mnt/extra-addons
# Mount config file
- ./config/odoo.dev.conf:/etc/odoo/odoo.conf
# Persist filestore for attachments
- odoo-dev-data:/var/lib/odoo
environment:
- HOST=db
- USER=odoo
- PASSWORD=odoo
# Enable debug mode for development
command: ["--dev=reload,qweb,werkzeug,xml"]
db:
image: postgres:15
container_name: odoo-dev-db
environment:
- POSTGRES_USER=odoo
- POSTGRES_PASSWORD=odoo
- POSTGRES_DB=postgres
ports:
- "5432:5432"
volumes:
- postgres-dev-data:/var/lib/postgresql/data
volumes:
odoo-dev-data:
postgres-dev-data:VS Code Configuration
Configure VS Code for optimal Odoo development with Python extensions and debugging support.
{
"python.defaultInterpreterPath": "/usr/bin/python3",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.linting.pylintArgs": [
"--load-plugins=pylint_odoo",
"--rcfile=.pylintrc"
],
"python.formatting.provider": "black",
"python.formatting.blackArgs": ["--line-length", "120"],
"editor.formatOnSave": true,
"files.associations": {
"*.xml": "xml"
},
"[xml]": {
"editor.defaultFormatter": "redhat.vscode-xml"
},
"xml.validation.enabled": true,
"python.analysis.extraPaths": [
"/opt/odoo/odoo",
"/opt/odoo/addons"
]
}{
"version": "0.2.0",
"configurations": [
{
"name": "Odoo: Debug",
"type": "python",
"request": "launch",
"program": "/opt/odoo/odoo-bin",
"args": [
"-c", "/etc/odoo/odoo.conf",
"-d", "odoo_dev",
"--dev=reload,qweb,werkzeug,xml"
],
"console": "integratedTerminal",
"justMyCode": false
},
{
"name": "Odoo: Run Tests",
"type": "python",
"request": "launch",
"program": "/opt/odoo/odoo-bin",
"args": [
"-c", "/etc/odoo/odoo.conf",
"-d", "odoo_test",
"--test-enable",
"--stop-after-init",
"-i", "your_module"
],
"console": "integratedTerminal"
}
]
}PyCharm Configuration
For PyCharm Professional users, configure the Odoo run configuration:
1. Set Python Interpreter
Settings > Project > Python Interpreter > Add the Docker or local Python environment with Odoo dependencies.
2. Add Odoo Source Roots
Mark the odoo/ and addons/ directories as Source Roots for proper code navigation and autocomplete.
3. Configure Run Configuration
Script: odoo-bin, Parameters: -c odoo.conf -d dev_db --dev=reload,qweb,werkzeug,xml
Git Branching Strategy for Odoo
A clear branching strategy prevents merge conflicts and ensures code quality. This modified Git Flow approach works well for Odoo projects of all sizes.
Branch Structure
main/master (production)
|
+-- develop (staging/integration)
|
+-- feature/inventory-widget
|
+-- feature/custom-reports
|
+-- bugfix/invoice-calculation
|
+-- release/v2.1.0
Branch Naming Conventions:
---------------------------
feature/module-name-description New features or modules
bugfix/issue-number-description Bug fixes
hotfix/critical-issue Production emergency fixes
release/vX.Y.Z Release preparation branches
main / master
Always reflects production. Only merge from release branches or hotfixes. Protected with required reviews.
- - Direct commits blocked
- - Requires PR approval
- - Triggers production deploy
develop
Integration branch for staging. Features merge here first for testing before production release.
- - Auto-deploys to staging
- - Requires PR approval
- - Integration testing happens here
feature/*
Short-lived branches for new development. Created from develop, merged back via PR.
- - One feature per branch
- - Delete after merge
- - Run CI on every push
release/*
Preparation for production release. Final testing, version bumps, and documentation updates.
- - Created from develop
- - Merged to both main and develop
- - Tag with version number
Branch Protection Rules
# GitHub Branch Protection Settings
## main branch:
- Require pull request reviews before merging: Yes
- Required approving reviews: 2
- Dismiss stale pull request approvals: Yes
- Require status checks to pass: Yes
- Required checks: lint, test, build
- Require branches to be up to date: Yes
- Include administrators: Yes
- Restrict who can push: Release managers only
## develop branch:
- Require pull request reviews before merging: Yes
- Required approving reviews: 1
- Require status checks to pass: Yes
- Required checks: lint, test
- Allow force pushes: No
- Allow deletions: NoBranch Naming Best Practices
- - Use lowercase with hyphens:
feature/sales-report-export - - Include ticket number when applicable:
bugfix/OD-123-fix-invoice - - Keep names short but descriptive
- - Delete branches after merging to keep repo clean
Staging Environment Setup
A staging environment mirrors production, allowing you to test changes with realistic data and configuration before going live. This catches issues that only appear in production-like conditions.
Staging Requirements
Separate Server/Container
Isolated from production infrastructure
Own PostgreSQL Database
Never share database with production
Same Odoo Version
Match production Odoo and Python versions exactly
Dedicated URL
staging.yourcompany.com or similar
Test Data
Sanitized copy of production data
Email Disabled/Redirected
Prevent accidental emails to real customers
Staging Configuration
[options]
; Staging Environment Configuration
admin_passwd = $STAGING_ADMIN_PASSWORD
db_host = staging-db.yourcompany.internal
db_port = 5432
db_user = odoo_staging
db_password = False ; Use environment variable
db_name = odoo_staging
; Paths
addons_path = /opt/odoo/odoo/addons,/opt/odoo/custom-addons
data_dir = /var/lib/odoo-staging
; Server settings
http_port = 8069
longpolling_port = 8072
proxy_mode = True
; Workers (smaller than production)
workers = 2
max_cron_threads = 1
; Logging
logfile = /var/log/odoo/staging.log
log_level = debug
log_handler = :DEBUG
; Email - CRITICAL: Disable outgoing emails
smtp_server = False
; Or redirect all emails to test mailbox:
; smtp_server = smtp.mailtrap.io
; smtp_port = 2525
; smtp_user = your_mailtrap_user
; smtp_password = your_mailtrap_password
; Development/Debug features (optional)
dev_mode = reload,qwebDatabase Cloning Script
Periodically refresh staging with production data. Always sanitize sensitive information.
#!/bin/bash
#
# Clone production database to staging with data sanitization
#
set -e
# Configuration
PROD_DB_HOST="prod-db.yourcompany.internal"
STAGING_DB_HOST="staging-db.yourcompany.internal"
DB_USER="odoo"
PROD_DB="odoo_production"
STAGING_DB="odoo_staging"
echo "Starting production to staging clone..."
# Stop staging Odoo
echo "Stopping staging Odoo service..."
sudo systemctl stop odoo-staging
# Create backup of production
echo "Dumping production database..."
pg_dump -h $PROD_DB_HOST -U $DB_USER -Fc $PROD_DB > /tmp/prod_backup.dump
# Drop and recreate staging database
echo "Recreating staging database..."
PGPASSWORD=$STAGING_DB_PASSWORD psql -h $STAGING_DB_HOST -U $DB_USER -c "DROP DATABASE IF EXISTS $STAGING_DB;"
PGPASSWORD=$STAGING_DB_PASSWORD psql -h $STAGING_DB_HOST -U $DB_USER -c "CREATE DATABASE $STAGING_DB OWNER $DB_USER;"
# Restore to staging
echo "Restoring to staging..."
pg_restore -h $STAGING_DB_HOST -U $DB_USER -d $STAGING_DB /tmp/prod_backup.dump
# Sanitize sensitive data
echo "Sanitizing data..."
PGPASSWORD=$STAGING_DB_PASSWORD psql -h $STAGING_DB_HOST -U $DB_USER -d $STAGING_DB << 'EOF'
-- Reset all user passwords to 'staging123'
UPDATE res_users SET password = 'staging123' WHERE id > 1;
-- Anonymize customer emails
UPDATE res_partner
SET email = CONCAT('staging_', id, '@example.com')
WHERE email IS NOT NULL AND email != '';
-- Clear sensitive payment data
TRUNCATE payment_token CASCADE;
-- Disable all outgoing mail servers
UPDATE ir_mail_server SET active = false;
-- Update system parameters for staging
UPDATE ir_config_parameter
SET value = 'https://staging.yourcompany.com'
WHERE key = 'web.base.url';
-- Clear scheduled actions that might cause issues
UPDATE ir_cron SET active = false
WHERE id IN (
SELECT id FROM ir_cron
WHERE name ILIKE '%mail%' OR name ILIKE '%email%'
);
EOF
# Sync filestore (optional - can be large)
echo "Syncing filestore..."
rsync -avz --delete \
prod-server:/var/lib/odoo/filestore/$PROD_DB/ \
/var/lib/odoo-staging/filestore/$STAGING_DB/
# Fix permissions
sudo chown -R odoo:odoo /var/lib/odoo-staging
# Start staging Odoo
echo "Starting staging Odoo..."
sudo systemctl start odoo-staging
# Cleanup
rm /tmp/prod_backup.dump
echo "Clone complete! Staging is now a sanitized copy of production."
echo "All user passwords have been reset to 'staging123'"Data Sanitization is Critical
URL Conventions
| Environment | URL Pattern | Purpose |
|---|---|---|
| Production | erp.yourcompany.com | Live business operations |
| Staging | staging.yourcompany.com | QA and client testing |
| Development | dev.yourcompany.com | Developer integration testing |
| Local | localhost:8069 | Individual development |
CI/CD Pipeline Configuration
Automate testing and deployment with CI/CD pipelines. This ensures every code change is validated before merging and deployments are consistent and repeatable.
GitHub Actions Workflow
name: Odoo CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
env:
ODOO_VERSION: "17.0"
PYTHON_VERSION: "3.10"
jobs:
lint:
name: Code Quality
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Install linting tools
run: |
pip install flake8 pylint pylint-odoo black isort
- name: Run flake8
run: |
flake8 addons/ --max-line-length=120 --ignore=E501,W503
- name: Run pylint-odoo
run: |
pylint addons/*/ --load-plugins=pylint_odoo \
--disable=all \
--enable=odoolint \
--rcfile=.pylintrc || true
- name: Check formatting with black
run: |
black --check --line-length 120 addons/
test:
name: Unit Tests
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:15
env:
POSTGRES_USER: odoo
POSTGRES_PASSWORD: odoo
POSTGRES_DB: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
- name: Install Odoo dependencies
run: |
sudo apt-get update
sudo apt-get install -y wkhtmltopdf libldap2-dev libsasl2-dev
pip install -r requirements.txt
- name: Clone Odoo
run: |
git clone --depth 1 --branch ${{ env.ODOO_VERSION }} \
https://github.com/odoo/odoo.git /tmp/odoo
- name: Run Odoo tests
env:
PGHOST: localhost
PGUSER: odoo
PGPASSWORD: odoo
run: |
/tmp/odoo/odoo-bin \
-d test_db \
--test-enable \
--stop-after-init \
--log-level=test \
-i $(ls -d addons/*/ | xargs -n1 basename | paste -sd,) \
--addons-path=/tmp/odoo/addons,/tmp/odoo/odoo/addons,./addons
deploy-staging:
name: Deploy to Staging
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/develop' && github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Deploy to staging server
uses: appleboy/[email protected]
with:
host: ${{ secrets.STAGING_HOST }}
username: ${{ secrets.STAGING_USER }}
key: ${{ secrets.STAGING_SSH_KEY }}
script: |
cd /opt/odoo/custom-addons
git fetch origin develop
git checkout develop
git pull origin develop
sudo systemctl restart odoo-staging
- name: Update Odoo modules
uses: appleboy/[email protected]
with:
host: ${{ secrets.STAGING_HOST }}
username: ${{ secrets.STAGING_USER }}
key: ${{ secrets.STAGING_SSH_KEY }}
script: |
# Wait for Odoo to start
sleep 30
# Update all custom modules
/opt/odoo/odoo-bin -c /etc/odoo/staging.conf \
-d odoo_staging \
-u all \
--stop-after-init
sudo systemctl restart odoo-staging
- name: Notify on success
uses: slackapi/[email protected]
with:
payload: |
{
"text": "Staging deployed successfully from develop branch"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
deploy-production:
name: Deploy to Production
runs-on: ubuntu-latest
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: production
steps:
- uses: actions/checkout@v4
- name: Create backup before deploy
uses: appleboy/[email protected]
with:
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.PROD_USER }}
key: ${{ secrets.PROD_SSH_KEY }}
script: |
/opt/odoo/scripts/backup.sh
- name: Deploy to production
uses: appleboy/[email protected]
with:
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.PROD_USER }}
key: ${{ secrets.PROD_SSH_KEY }}
script: |
cd /opt/odoo/custom-addons
git fetch origin main
git checkout main
git pull origin main
sudo systemctl restart odoo
- name: Update modules
uses: appleboy/[email protected]
with:
host: ${{ secrets.PROD_HOST }}
username: ${{ secrets.PROD_USER }}
key: ${{ secrets.PROD_SSH_KEY }}
script: |
sleep 30
/opt/odoo/odoo-bin -c /etc/odoo/odoo.conf \
-d odoo_production \
-u all \
--stop-after-init
sudo systemctl restart odooGitLab CI Configuration
If you're using GitLab for your repositories, GitLab CI provides powerful pipeline features. For more details on GitLab-specific Odoo workflows, see our Odoo GitLab CI/CD guide.
stages:
- lint
- test
- deploy
variables:
ODOO_VERSION: "17.0"
PYTHON_VERSION: "3.10"
POSTGRES_DB: test_db
POSTGRES_USER: odoo
POSTGRES_PASSWORD: odoo
.default_rules:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "develop"
- if: $CI_COMMIT_BRANCH == "main"
lint:
stage: lint
image: python:3.10
extends: .default_rules
before_script:
- pip install flake8 pylint pylint-odoo black
script:
- flake8 addons/ --max-line-length=120
- black --check --line-length 120 addons/
- pylint addons/*/ --load-plugins=pylint_odoo --disable=all --enable=odoolint || true
test:
stage: test
image: python:3.10
extends: .default_rules
services:
- postgres:15
variables:
PGHOST: postgres
PGUSER: odoo
PGPASSWORD: odoo
before_script:
- apt-get update && apt-get install -y wkhtmltopdf libldap2-dev libsasl2-dev
- pip install -r requirements.txt
- git clone --depth 1 --branch $ODOO_VERSION https://github.com/odoo/odoo.git /tmp/odoo
script:
- |
/tmp/odoo/odoo-bin \
-d test_db \
--test-enable \
--stop-after-init \
--log-level=test \
-i $(ls -d addons/*/ | xargs -n1 basename | paste -sd,) \
--addons-path=/tmp/odoo/addons,/tmp/odoo/odoo/addons,./addons
deploy_staging:
stage: deploy
image: alpine:latest
rules:
- if: $CI_COMMIT_BRANCH == "develop"
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$STAGING_SSH_KEY" | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
script:
- ssh -o StrictHostKeyChecking=no $STAGING_USER@$STAGING_HOST "
cd /opt/odoo/custom-addons &&
git pull origin develop &&
sudo systemctl restart odoo-staging
"
environment:
name: staging
url: https://staging.yourcompany.com
deploy_production:
stage: deploy
image: alpine:latest
rules:
- if: $CI_COMMIT_BRANCH == "main"
when: manual
before_script:
- apk add --no-cache openssh-client
- eval $(ssh-agent -s)
- echo "$PROD_SSH_KEY" | ssh-add -
script:
- ssh -o StrictHostKeyChecking=no $PROD_USER@$PROD_HOST "
/opt/odoo/scripts/backup.sh &&
cd /opt/odoo/custom-addons &&
git pull origin main &&
sudo systemctl restart odoo
"
environment:
name: production
url: https://erp.yourcompany.comAutomated Testing Configuration
Configure Odoo test settings for consistent CI runs.
# Import all test classes
from . import test_models
from . import test_wizards
from . import test_reports# -*- coding: utf-8 -*-
from odoo.tests.common import TransactionCase, tagged
from odoo.exceptions import ValidationError
@tagged('post_install', '-at_install')
class TestYourModel(TransactionCase):
"""Test cases for your_module models."""
@classmethod
def setUpClass(cls):
"""Set up test fixtures."""
super().setUpClass()
cls.partner = cls.env['res.partner'].create({
'name': 'Test Partner',
'email': '[email protected]',
})
cls.your_model = cls.env['your.model'].create({
'name': 'Test Record',
'partner_id': cls.partner.id,
})
def test_create_record(self):
"""Test record creation."""
record = self.env['your.model'].create({
'name': 'New Record',
'partner_id': self.partner.id,
})
self.assertTrue(record.id)
self.assertEqual(record.name, 'New Record')
def test_compute_field(self):
"""Test computed field calculation."""
self.your_model.amount = 100
self.your_model.quantity = 5
self.assertEqual(self.your_model.total, 500)
def test_constraint_validation(self):
"""Test model constraints raise errors."""
with self.assertRaises(ValidationError):
self.env['your.model'].create({
'name': '', # Should fail - name required
'partner_id': self.partner.id,
})
def test_action_method(self):
"""Test action method behavior."""
self.your_model.action_confirm()
self.assertEqual(self.your_model.state, 'confirmed')Test Tags Explained
post_install: Run after module installation-at_install: Do not run during installationstandard: Include in standard test runs- Use custom tags like
@tagged('slow')for long-running tests
Staging to Production Workflow
Moving code from staging to production requires careful planning and execution. Follow this workflow to minimize risk and ensure smooth deployments.
Pre-Deployment Checklist
Code Review Completed
All PRs reviewed and approved by at least one team member.
Tests Passing
All automated tests pass in CI pipeline.
Staging QA Complete
Manual testing in staging environment signed off.
Database Migration Tested
Module updates run successfully on staging.
Rollback Plan Ready
Know how to revert if issues occur.
Backup Created
Fresh production backup taken before deployment.
Stakeholders Notified
Team and users aware of deployment window.
Module Update Procedures
#!/bin/bash
#
# Production Deployment Script
#
set -e
echo "=== Production Deployment Starting ==="
echo "Time: $(date)"
# Configuration
ODOO_CONFIG="/etc/odoo/odoo.conf"
DB_NAME="odoo_production"
MODULES_TO_UPDATE="your_module,another_module" # or "all" for all modules
# Step 1: Create backup
echo "Step 1: Creating backup..."
/opt/odoo/scripts/backup.sh
echo "Backup completed"
# Step 2: Pull latest code
echo "Step 2: Pulling latest code..."
cd /opt/odoo/custom-addons
git fetch origin main
git checkout main
git pull origin main
echo "Code updated to: $(git rev-parse --short HEAD)"
# Step 3: Stop Odoo gracefully
echo "Step 3: Stopping Odoo..."
sudo systemctl stop odoo
sleep 10
# Step 4: Run module updates
echo "Step 4: Updating modules..."
/opt/odoo/odoo-bin -c $ODOO_CONFIG \
-d $DB_NAME \
-u $MODULES_TO_UPDATE \
--stop-after-init \
--log-level=info
# Step 5: Start Odoo
echo "Step 5: Starting Odoo..."
sudo systemctl start odoo
sleep 30
# Step 6: Health check
echo "Step 6: Running health check..."
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8069/web/health)
if [ "$HTTP_STATUS" -eq 200 ]; then
echo "Health check passed!"
else
echo "WARNING: Health check returned $HTTP_STATUS"
echo "Check logs: sudo journalctl -u odoo -f"
fi
echo "=== Deployment Complete ==="
echo "Time: $(date)"Rollback Strategy
When deployments go wrong, quick rollback minimizes impact. Always have a tested rollback procedure.
#!/bin/bash
#
# Emergency Rollback Script
#
set -e
echo "=== EMERGENCY ROLLBACK ==="
echo "This will restore the previous deployment."
read -p "Are you sure? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
echo "Rollback cancelled."
exit 1
fi
# Configuration
BACKUP_DIR="/opt/odoo/backups"
ODOO_CONFIG="/etc/odoo/odoo.conf"
DB_NAME="odoo_production"
# Find most recent backup
LATEST_BACKUP=$(ls -t $BACKUP_DIR/full_backup_*.tar.gz | head -1)
echo "Using backup: $LATEST_BACKUP"
# Stop Odoo
echo "Stopping Odoo..."
sudo systemctl stop odoo
# Restore code to previous version
echo "Reverting code..."
cd /opt/odoo/custom-addons
git checkout HEAD~1
# Restore database (optional - only if DB changes need reverting)
read -p "Restore database from backup? (yes/no): " restore_db
if [ "$restore_db" == "yes" ]; then
echo "Restoring database..."
tar -xzf $LATEST_BACKUP -C /tmp/
sudo -u postgres dropdb $DB_NAME
sudo -u postgres createdb -O odoo $DB_NAME
sudo -u postgres pg_restore -d $DB_NAME /tmp/db_*.dump
rm /tmp/db_*.dump /tmp/filestore_*.tar.gz
fi
# Start Odoo
echo "Starting Odoo..."
sudo systemctl start odoo
sleep 30
# Verify
echo "Verifying service..."
sudo systemctl status odoo
echo "=== Rollback Complete ==="
echo "Please verify the system manually."Deployment Best Practices
- - Deploy during low-traffic periods
- - Update modules one at a time for large changes
- - Monitor logs during and after deployment
- - Have database admin on standby for migration issues
- - Document each deployment for future reference
Skip the Setup with OEC.sh Staging
Setting up and maintaining staging environments takes significant time and DevOps expertise. OEC.sh provides built-in staging environments with one-click creation and easy promotion to production.
One-Click Staging
Create staging environments instantly from dashboard
Database Cloning
Clone production data to staging with auto-sanitization
Git Integration
Auto-deploy from branches with webhook triggers
Easy Promotion
Promote staging to production with one click
Automatic Backups
Pre-deployment backups created automatically
Rollback Support
One-click rollback to previous version
Self-Managed Staging
- - Hours to set up
- - Manual server maintenance
- - DIY database cloning
- - Custom deployment scripts
OEC.sh Staging
- Minutes to create
- Fully managed
- One-click clone
- Git auto-deploy
Odoo.sh Staging
- - Built-in branches
- - Limited to Odoo.sh hosting
- - Higher per-user pricing
- - Single cloud provider
Frequently Asked Questions
What is a staging environment for Odoo?
A staging environment is a pre-production replica of your live Odoo system where you test code changes, module updates, and new features before deploying to production. It should mirror your production setup with its own dedicated server, PostgreSQL database, and URL (e.g., staging.yourcompany.com). Staging uses sanitized production data to simulate real-world conditions while protecting sensitive customer information. This testing ground catches bugs and compatibility issues before they affect your live business operations.
How do I set up CI/CD for Odoo?
Setting up CI/CD for Odoo involves: 1) Choose a platform (GitHub Actions or GitLab CI), 2) Configure automated tests that run on every commit (linting with pylint-odoo, unit tests with Odoo's test framework, XML validation), 3) Set up automated deployment to staging when changes merge to the develop branch, 4) Implement manual approval gates for production deployments. Use Docker containers in your CI pipeline for consistent test environments. Store credentials and SSH keys in your platform's secrets management. For detailed configurations, see our guides on Odoo Docker deployment and GitLab CI.
Should I use GitHub Actions or GitLab CI?
Both GitHub Actions and GitLab CI work excellently for Odoo. Choose GitHub Actions if your team already uses GitHub for code hosting, prefers the marketplace ecosystem of pre-built actions, and wants simple YAML configuration. Choose GitLab CI if you want an all-in-one DevOps platform, need more advanced pipeline features (parent-child pipelines, manual gates), or prefer tighter integration between code and CI/CD. For Odoo specifically, both platforms support Docker-based testing and deployment equally well. The choice often depends on your existing tooling and team preferences rather than technical limitations.
How do I clone production to staging?
To clone production to staging: 1) Stop the staging Odoo service, 2) Create a pg_dump backup of your production database, 3) Drop and recreate the staging database, 4) Restore the backup to staging, 5) Run SQL scripts to sanitize sensitive data (anonymize emails, reset passwords, disable mail servers, clear payment tokens), 6) Optionally sync the filestore with rsync, 7) Restart staging Odoo. Automate this process with a bash script that runs weekly or monthly. Never skip data sanitization - it's critical for GDPR compliance and preventing accidental customer communications from staging. For detailed scripts and best practices, see our Odoo backup and recovery guide.
What's the best workflow for Odoo development?
The best Odoo development workflow uses Git Flow with staging: 1) Developers create feature branches from develop, 2) Code changes go through automated CI tests (linting, unit tests), 3) Features merge to develop branch via pull request with peer review, 4) Develop branch auto-deploys to staging for QA testing, 5) After staging validation, create a release branch, 6) Release branch merges to main/master which triggers production deployment, 7) Tag releases with version numbers for easy rollbacks. Use Docker for consistent local development environments. This workflow separates dev/staging/production clearly, enables parallel development, and ensures code quality through automated testing and manual review gates.
How do I deploy from staging to production?
To deploy from staging to production: 1) Validate all changes thoroughly in staging with QA testing and stakeholder approval, 2) Create a backup of production database and code, 3) Merge your tested changes from develop/release branch to main branch, 4) SSH to production server or trigger automated deployment pipeline, 5) Pull latest code from main branch, 6) Restart Odoo with module update flag (-u module_name or -u all), 7) Monitor logs and verify functionality, 8) Have a rollback plan ready if issues arise. For critical updates, deploy during low-traffic windows. Consider blue-green deployments or rolling updates for zero-downtime. OEC.sh automates this entire process with one-click promotion from staging to production.
Can I use GitHub Actions with Odoo?
Yes, GitHub Actions works excellently with Odoo. You can automate linting (pylint, flake8), run Odoo unit tests, check XML syntax, validate module manifests, and deploy to staging or production. Use the official Odoo Docker images or build custom images with your dependencies. Store secrets like database credentials and SSH keys in GitHub Secrets. The workflow runs on every push to feature branches, automatically deploys to staging when merging to develop, and requires manual approval for production deployments. See our complete GitHub Actions configuration examples in this guide.
How do I run Odoo tests in CI/CD pipelines?
Odoo has a built-in test framework based on Python unittest. Run tests with: odoo-bin -d test_db --test-enable --stop-after-init -i your_module. For CI/CD, spin up a temporary PostgreSQL database service, install your module with tests enabled, and check the exit code. You can also use pytest-odoo for more advanced testing features and better reporting. In GitHub Actions or GitLab CI, use Docker services to run PostgreSQL alongside your test container. Cache pip dependencies between runs to speed up pipeline execution.
Ready to Streamline Your Odoo Workflow?
Skip the infrastructure complexity. OEC.sh provides staging environments, Git integration, and automated deployments out of the box.
Related Guides
Odoo Docker Deployment
Production-ready Docker Compose setup for Odoo with PostgreSQL.
GitLab CI/CD for Odoo
Complete GitLab CI configuration for Odoo testing and deployment.
Backup and Recovery
Automated backup strategies and disaster recovery for Odoo.
How to Deploy Odoo
Complete guide to deploy Odoo on any cloud server from scratch.
SSL and Custom Domains
Configure HTTPS, SSL certificates, and custom domains for Odoo.
Performance Optimization
Tune PostgreSQL and Odoo for maximum performance.