Odoo Deploy Automation and Staging: Complete Guide
Master Odoo development workflows with staging environments, deploy 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 deploy 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
DEPLOY 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 a safe placeholder
UPDATE res_users SET password = 'YOUR_STAGING_PASSWORD' 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 the staging placeholder"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 |
Deploy Pipeline Configuration
Automate testing and deployment with deploy 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/ssh-action@v1.0.3
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/ssh-action@v1.0.3
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/slack-github-action@v1.26.0
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/ssh-action@v1.0.3
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/ssh-action@v1.0.3
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/ssh-action@v1.0.3
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, its built-in CI handles Odoo pipelines well. For GitLab-specific workflows, see our Odoo GitLab deploy pipeline 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': 'test@example.com',
})
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 email and crons switched off
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 mirrors your production setup with its own server, database, and URL, using sanitized data to catch bugs before they hit live users.
How do I set up deploy automation for Odoo?
Setting up deploy automation for Odoo involves four steps: 1) Choose a platform (GitHub Actions or GitLab CI), 2) Configure automated tests on every commit (linting, unit tests, XML validation), 3) Deploy to staging when changes merge to develop, 4) Add manual approval gates for production.
Should I use GitHub Actions or GitLab CI?
Both work excellently for Odoo. Choose GitHub Actions if your team already hosts code on GitHub and wants a marketplace of pre-built actions. Choose GitLab CI if you prefer an all-in-one DevOps platform with advanced pipeline features. The right pick usually comes down to existing tooling, not technical limits.
How do I clone production to staging?
To clone production to staging: 1) Stop the staging Odoo service, 2) pg_dump the production database, 3) Drop and recreate the staging database, 4) Restore the backup, 5) Run SQL scripts to sanitize sensitive data (anonymize emails, reset passwords, disable mail servers), 6) Sync the filestore, 7) Restart staging.
What's the best workflow for Odoo development?
The best Odoo workflow uses Git Flow with staging: feature branches merge to develop (runs automated tests), develop auto-deploys to staging for QA, a release branch is cut, that release merges to main which deploys to production, and each release is tagged with a version for rollbacks.
How do I deploy from staging to production?
To deploy from staging to production: 1) Validate changes in staging with QA and stakeholder sign-off, 2) Back up the production database and code, 3) Merge your release branch to main, 4) Pull the new code on production, 5) Restart Odoo with the module update flag, 6) Monitor logs.
Can I use GitHub Actions with Odoo?
Yes. GitHub Actions can lint, run Odoo unit tests, validate XML and module manifests, and deploy to staging or production. Use the official Odoo Docker images, store credentials in GitHub Secrets, and gate production deploys behind manual approval. This guide includes complete workflow examples.
How do I run Odoo tests in deploy pipelines?
Odoo uses a Python unittest-based test framework. Run tests with: odoo-bin -d test_db --test-enable --stop-after-init -i your_module. In a pipeline, start a temporary PostgreSQL service, install the module with tests enabled, and check the exit code. pytest-odoo adds richer reporting.
Ready to Simplify 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 Deploy Pipelines 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.
Bitbucket Deploy Pipelines for Odoo
Deploy Odoo with Bitbucket Pipelines.