Tutorials/Development Lifecycle & Devops

Development Lifecycle & Devops

Frappe Development Lifecycle

Frappe follows a structured development lifecycle that separates concerns across environments — from local development to staging to production — using the bench CLI as the primary operational tool.

1. Environments

Each environment is an independent bench with its own sites, databases, and app versions. No code is deployed directly to production without passing through staging.

2. How Check-ins Are Done

All Frappe custom app code lives in a git repository. The check-in process follows standard git branching with Frappe-specific considerations:

Branching Strategy

What Gets Committed

  • Python controllers — doctype_name.py with business logic
  • JSON DocType definitions — schema, fields, permissions (doctype_name.json)
  • JavaScript client scripts — doctype_name.js for form-side logic
  • Fixtures — exported Custom Fields, Workflows, Print Formats as JSON
  • Patches — one-time data migration scripts in patches.txt
  • hooks.py — app-level configuration and overrides

Check-in Workflow

# 1. Create feature branch
git checkout -b feature/record-referral-enhancements

# 2. Make changes to DocType/Python/JS

# 3. Export any DocType changes to JSON (keeps schema in git)

bench export-fixtures --app custom_app

# 4. Stage and commit

git add .

git commit -m "feat: add referral amount calculation to CustomDocType"

# 5. Push and open Pull Request to develop

git push origin feature/record-referral-enhancements

Code Review checklist before merge:

  • No direct changes to erpnext or frappe app code — only custom app
  • DocType JSON re-exported after any field/permission changes
  • Patches written for any data migrations
  • No hardcoded site names or environment-specific values
  • Background jobs use frappe.enqueue() — not blocking calls

3. How Rollout to Production is Done

Production deployments in Frappe use the bench update command combined with a pre-defined release process. No hot-patching of live files.

Standard Rollout Steps

# Step 1: Pull latest code for all apps on the bench

bench update --pull

# Step 2: Run database migrations (applies new columns, patches)

bench update --patch

# Step 3: Build JS/CSS assets

bench build --app custom_app

# Step 4: Restart services (Gunicorn workers + RQ workers)

bench restart

# Combined (most common for minor updates):

bench update --reset

Rollout Process with Maintenance Window

Zero-Downtime Deployments (Advanced)

  • Use Kubernetes rolling updates — new pods with updated image replace old ones gradually
  • Keep DB migrations backward-compatible — new columns are nullable, old code still works
  • Use feature flags in frappe.conf to enable new features post-deployment
  • Blue-green deployment: spin up new bench, switch Nginx upstream, keep old bench as fallback

Hotfix Process

# Branch off main (not develop) for critical fixes

git checkout -b hotfix/fix-fee-calculation main

# ... make fix ...

git commit -m "fix: correct fee calculation for partial payments"

# Merge to both main AND develop

git checkout main && git merge hotfix/fix-fee-calculation

git checkout develop && git merge hotfix/fix-fee-calculation

# Deploy to production immediately

bench update --patch && bench restart

4. Full Development Lifecycle

Environment Promotion Flow

feature/* ──► develop ──► staging ──► main ──► production
Environment Promotion Flow
Environment Promotion Flow — feature → develop → staging → main → production

UAT sign-off Release tag

Key bench CLI Commands Reference

Frappe Development Lifecycle

Frappe follows a structured development lifecycle — from local development to production — with clear stages, tooling, and conventions enforced by the bench CLI.

1. Environments

Each environment runs a separate bench with its own MariaDB database, Redis instance, and site config. No shared state between environments.

2. Local Development Setup

# Install bench

pip install frappe-bench

# Initialise a new bench

bench init frappe-bench --frappe-branch version-16

cd frappe-bench

# Add ERPNext and custom app

bench get-app erpnext --branch version-16

bench get-app custom_app https://github.com/hybrowlabs/custom_app

# Create a new site

bench new-site yoursite.local --install-app erpnext --install-app custom_app

# Start development server

bench start

3. Code Check-in Process

All Frappe customisations live in the custom app repository (e.g., custom_app). The check-in workflow follows standard git practices:

# Create a feature branch

git checkout -b feature/record-referral-module

# Make changes — DocType JSON, Python controller, hooks.py

# Export DocType changes as fixtures

bench --site yoursite.local export-fixtures

# Stage and commit

git add .

git commit -m "feat: add Custom DocType doctype with lifecycle hooks"

# Push and raise Pull Request

git push origin feature/record-referral-module

4. Staging Deployment

After PR review and merge to the develop or staging branch, deploy to the staging environment:

# On staging server — pull latest code

cd /home/frappe/frappe-bench

bench update --pull --patch --build

# Or for the custom app only (faster)

bench update --apps custom_app

# Run migrations if schema changed

bench --site staging.yoursite.erpnext.com migrate

# Clear cache

bench --site staging.yoursite.erpnext.com clear-cache

Staging is used for client UAT (User Acceptance Testing). stakeholders validate functionality before production sign-off.

5. Production Rollout

Production deployments follow a controlled process to minimise downtime and risk:

# Step 1: Enable maintenance mode (shows maintenance page to users)

bench --site yoursite.erpnext.com set-maintenance-mode on

# Step 2: Pull latest code from release branch

bench update --pull --patch --build --restart-supervisor

# Step 3: Run database migrations

bench --site yoursite.erpnext.com migrate

# Step 4: Clear all caches

bench --site yoursite.erpnext.com clear-cache

bench --site yoursite.erpnext.com clear-website-cache

# Step 5: Disable maintenance mode

bench --site yoursite.erpnext.com set-maintenance-mode off

# Step 6: Restart services

sudo supervisorctl restart all

Typical downtime: 2–5 minutes for minor releases. Zero-downtime blue-green deployments are possible on Kubernetes with rolling updates.

6. Branching Strategy

7. Patch Management

One-time data migrations are handled via patches — Python scripts that run exactly once per site during bench migrate:

# patches/v1_0/backfill_custom_doctype_status.py

import frappe

def execute():
    frappe.db.sql("""
        UPDATE `tabCustom DocType`
        SET status = "Pending"
        WHERE status IS NULL OR status = ""
    """)
    frappe.db.commit()

Patches are registered in patches.txt and executed automatically during bench migrate — never run twice on the same site.

For , a CI/CD pipeline via GitHub Actions or GitLab CI is recommended:

Need help with your workflow setup?

If you're stuck or want help applying these guides to your setup, our team can assist with configuration, customization, and workflow implementation.

WhatsApp