Use when running bench commands, managing sites, configuring multi-tenancy, or setting up domains. Prevents misconfigured bench environments, broken site routing, and DNS mismatches. Covers bench CLI commands, site creation, bench init, multi-tenancy setup, DNS-based routing, common-site-config. Keywords: bench, site, multi-tenancy, domains, bench init, bench new-site, bench setup, common_site_config, bench command not working, site setup, multi-tenant, domain routing, new site..
Scanned 9/6/2026
Install to Claude Code
npx -y skills add OpenAEC-Foundation/ERPNext_Anthropic_Claude_Development_Skill_Package --skill frappe-ops-bench --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Frappe Ops Bench?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/openaec-foundation-frappe-ops-bench)More formats (shields.io, HTML) on the badges page.
---
name: frappe-ops-bench
description: >
Use when running bench commands, managing sites, configuring multi-tenancy, or setting up domains.
Prevents misconfigured bench environments, broken site routing, and DNS mismatches.
Covers bench CLI commands, site creation, bench init, multi-tenancy setup, DNS-based routing, common-site-config.
Keywords: bench, site, multi-tenancy, domains, bench init, bench new-site, bench setup, common_site_config, bench command not working, site setup, multi-tenant, domain routing, new site..
license: MIT
compatibility: "Claude Code, Claude.ai Projects, Claude API. Frappe v14-v16."
metadata:
author: OpenAEC-Foundation
version: "2.0"
---
# Bench CLI Complete Reference
Complete bench CLI reference for site management, app lifecycle, configuration, and multi-tenancy.
**Version**: v14/v15/v16
---
## Quick Reference: Essential Commands
| Task | Command |
|------|---------|
| Create bench | `bench init myproject --frappe-branch version-15` |
| Create site | `bench new-site mysite.localhost --admin-password admin` |
| Set default site | `bench use mysite.localhost` |
| Get app | `bench get-app erpnext --branch version-15` |
| Install app | `bench --site mysite install-app erpnext` |
| Start dev server | `bench start` |
| Run migrations | `bench --site mysite migrate` |
| Build assets | `bench build --app myapp` |
| Backup site | `bench --site mysite backup` |
| Restore backup | `bench --site mysite restore /path/to/backup.sql.gz` |
| Open console | `bench --site mysite console` |
| Open DB shell | `bench --site mysite mariadb` |
| Check scheduler | `bench doctor` |
| View pending jobs | `bench show-pending-jobs` |
| Update everything | `bench update` |
| Drop site | `bench drop-site mysite --force` |
---
## Workflow 1: Creating a New Bench
```bash
# Initialize bench with specific Frappe version
bench init myproject --frappe-branch version-15
# With Python version
bench init myproject --frappe-branch version-15 --python python3.11
# Enter bench directory (REQUIRED for all subsequent commands)
cd myproject
```
**What `bench init` creates:**
```
myproject/
├── apps/ # Installed Frappe apps (frappe is default)
├── sites/ # All sites and shared config
│ └── common_site_config.json
├── config/ # Redis, Procfile, supervisor configs
├── env/ # Python virtual environment
├── logs/ # Log files
└── Procfile # Process definitions for bench start
```
### Critical Rules
- **ALWAYS** specify `--frappe-branch` to pin Frappe version
- **ALWAYS** run commands from inside the bench directory
- **NEVER** run bench commands as root — use a dedicated frappe user
---
## Workflow 2: Site Management
### Creating Sites
```bash
# Basic site creation
bench new-site mysite.localhost --admin-password admin
# With specific database
bench new-site mysite.localhost --db-name mysite_db --admin-password admin
# With MariaDB root password
bench new-site mysite.localhost --mariadb-root-password rootpass --admin-password admin
# Install apps during creation
bench new-site mysite.localhost --admin-password admin --install-app erpnext
```
### Setting Default Site
```bash
bench use mysite.localhost
# OR set environment variable for current session:
export FRAPPE_SITE=mysite.localhost
```
### Dropping a Site
```bash
bench drop-site mysite.localhost --force
# Deletes database and archives site directory
```
### Site Directory Structure
```
sites/mysite.localhost/
├── site_config.json # Site-specific config (db credentials)
├── private/ # Auth-required files, backups
├── public/ # Publicly accessible files
├── locks/ # Scheduler lock files
└── task-logs/ # Scheduler task logs
```
---
## Workflow 3: App Management
```bash
# Download app from GitHub
bench get-app erpnext --branch version-15
bench get-app https://github.com/org/custom-app.git --branch main
# Install app on a site
bench --site mysite install-app erpnext
# List installed apps
bench --site mysite list-apps
# Remove app from site (creates backup first)
bench --site mysite uninstall-app custom_app
# Remove app from bench entirely
bench remove-app custom_app
# Switch app branch
bench switch-to-branch version-15 erpnext frappe
# Exclude app from updates
bench exclude-app custom_app
# Re-include app in updates
bench include-app custom_app
```
### Critical Rules
- **ALWAYS** `get-app` before `install-app` — get downloads, install activates
- **ALWAYS** backup before `uninstall-app` — it deletes app-related data
- **NEVER** manually delete app folders — use `bench remove-app`
---
## Workflow 4: bench update: What It Does
```bash
# Full update (pull + migrate + build + restart)
bench update
# Update specific app only
bench update --pull --app erpnext
# Skip build step
bench update --no-build
# Skip backup
bench update --no-backup
# Reset to upstream (DESTROYS local changes)
bench update --reset
```
**`bench update` executes these steps in order:**
1. Backup all sites
2. Pull latest code for all apps (`git pull`)
3. Install Python/Node requirements
4. Build static assets (`bench build`)
5. Run migrations on all sites (`bench migrate`)
6. Restart bench processes
### Critical Rules
- **ALWAYS** run `bench update` in a screen/tmux session — it takes time
- **NEVER** use `--reset` in production without understanding it does `git reset --hard`
- **ALWAYS** test updates on staging first
---
## Workflow 5: bench migrate
```bash
# Migrate specific site
bench --site mysite migrate
# Migrate all sites
bench --site all migrate
# Check if safe to migrate (no pending jobs)
bench --site mysite ready-for-migration
```
**What `bench migrate` does:**
1. Runs schema sync (DocType changes → database)
2. Runs patches (data migrations)
3. Rebuilds search index
4. Syncs translations
5. Rebuilds Dashboard cache
### When to Migrate
- After `bench update` (done automatically)
- After changing hooks.py
- After adding/modifying DocTypes
- After pulling code changes
- **NEVER** skip migrate after code changes — leads to schema mismatches
---
## Workflow 6: bench build
```bash
# Build all apps
bench build
# Build specific app
bench build --app myapp
# Build with bundle analyzer
bench build --app myapp --production
# Watch mode (auto-rebuild on file changes)
bench watch
```
### When to Build
- After changing JS/CSS files
- After `bench get-app` (done automatically)
- After modifying `package.json`
- **ALWAYS** build after modifying client-side assets
---
## Workflow 7: Console and Database Access
```bash
# IPython console (with Frappe loaded)
bench --site mysite console
# In console:
# >>> frappe.get_doc("Sales Invoice", "INV-001")
# >>> frappe.db.sql("SELECT name FROM `tabUser` LIMIT 5")
# Auto-reload on code changes
bench --site mysite console --autoreload
# MariaDB shell
bench --site mysite mariadb
# >>> SELECT name, email FROM tabUser LIMIT 5;
# PostgreSQL shell
bench --site mysite postgres
# Execute a method directly
bench --site mysite execute myapp.tasks.daily_cleanup
bench --site mysite execute myapp.api.process --kwargs '{"name": "INV-001"}'
# Make authenticated request as Administrator
bench --site mysite request GET /api/resource/User
```
---
## Workflow 8: Backup and Restore
```bash
# Backup (database + files)
bench --site mysite backup
# Creates: sites/mysite/private/backups/
# YYYY-MM-DD_HHMMSS-mysite-database.sql.gz
# YYYY-MM-DD_HHMMSS-mysite-files.tar
# YYYY-MM-DD_HHMMSS-mysite-private-files.tar
# Backup all sites
bench backup-all-sites
# Backup with encryption
bench --site mysite backup --backup-encryption-key mykey
# Restore from backup
bench --site mysite restore /path/to/database.sql.gz
# Restore with files
bench --site mysite restore /path/to/database.sql.gz \
--with-public-files /path/to/files.tar \
--with-private-files /path/to/private-files.tar
# Partial restore
bench --site mysite partial-restore /path/to/database.sql.gz
```
### Critical Rules
- **ALWAYS** backup before `bench update`, `uninstall-app`, or `drop-site`
- Backups older than 24 hours auto-deleted by default — configure `keep_backups_for_hours`
- **ALWAYS** test restore on a staging site before relying on a backup
---
## Workflow 9: Scheduler and Background Jobs
```bash
# Enable/disable scheduler
bench --site mysite scheduler enable
bench --site mysite scheduler disable
bench --site mysite scheduler pause
bench --site mysite scheduler resume
# Check scheduler health
bench doctor
# View queued jobs
bench show-pending-jobs
# Purge pending jobs
bench --site mysite purge-jobs
# Manually trigger scheduler event
bench --site mysite trigger-scheduler-event hourly
# Start worker manually (for debugging)
bench worker --queue short
```
---
## Workflow 10: Multi-Tenancy
### DNS-Based Routing (Recommended)
```bash
# Enable DNS multi-tenancy
bench config dns_multitenant on
# Create sites with proper hostnames
bench new-site site1.example.com --admin-password admin
bench new-site site2.example.com --admin-password admin
# Regenerate nginx config
bench setup nginx
# Reload nginx
sudo service nginx reload
```
Requests are routed by matching the `Host` header to site names.
### Port-Based Routing (Alternative)
```bash
bench config dns_multitenant off
bench new-site site2.localhost --admin-password admin
bench set-nginx-port site2.localhost 8082
bench setup nginx
sudo service nginx reload
```
### Custom Domain Mapping
```bash
# Add domain to site
bench setup add-domain site1.example.com --site mysite
bench setup nginx
sudo service nginx reload
```
---
## Configuration: common_site_config.json
Located at `sites/common_site_config.json` — applies to ALL sites.
### Essential Keys
| Key | Default | Purpose |
|-----|---------|---------|
| `background_workers` | 1 | Number of background job workers |
| `developer_mode` | false | Auto-sync DocType changes to files |
| `dns_multitenant` | false | Enable DNS-based multi-tenancy |
| `gunicorn_workers` | 2 | Web server worker count (min: 2) |
| `maintenance_mode` | 0 | Take all sites offline |
| `pause_scheduler` | 0 | Pause job scheduler |
| `serve_default_site` | — | Default site when host not matched |
| `server_script_enabled` | false | Enable Server Scripts |
| `scheduler_tick_interval` | 60 | Seconds between scheduler checks |
| `webserver_port` | 8000 | Development server port |
| `socketio_port` | 9000 | Socket.IO port |
| `live_reload` | false | Auto-reload on asset rebuild |
### Redis Configuration
| Key | Default |
|-----|---------|
| `redis_cache` | `redis://localhost:13000` |
| `redis_queue` | `redis://localhost:11000` |
| `redis_socketio` | `redis://localhost:13000` |
### Setting Config Values
```bash
# Set common config (all sites)
bench config set-common-config -c background_workers 4
bench config set-common-config -c developer_mode 1
# Set site-specific config
bench --site mysite set-config developer_mode 1
bench --site mysite set-config maintenance_mode 1
# View current config
bench --site mysite show-config
```
---
## Configuration: site_config.json
Per-site config at `sites/<sitename>/site_config.json`.
### Mandatory Keys
| Key | Purpose |
|-----|---------|
| `db_type` | `mariadb` or `postgres` |
| `db_name` | Database name |
| `db_password` | Database password |
### Important Optional Keys
| Key | Purpose |
|-----|---------|
| `admin_password` | Administrator initial password |
| `host_name` | Full site URL (with protocol) |
| `install_apps` | Apps to install on restore/reinstall |
| `allow_cors` | CORS origins (`"*"`, URL, or array) |
| `max_file_size` | Upload limit (default: 10MB) |
| `mute_emails` | Disable all outgoing email |
| `logging` | Debug level (0-2, level 2 shows SQL queries) |
### Environment Variable Overrides
Environment variables override config files. Key mappings: `FRAPPE_REDIS_QUEUE`, `FRAPPE_REDIS_CACHE`, `FRAPPE_DB_HOST`, `FRAPPE_DB_PORT`, `FRAPPE_DB_NAME`, `FRAPPE_DB_PASSWORD`.
**Priority**: Environment Variable > site_config.json > common_site_config.json > Default
---
## Production Setup
```bash
sudo bench setup production frappe-user # nginx + supervisor + fail2ban
bench setup lets-encrypt mysite.example.com # SSL
sudo bench restart # Restart services
bench disable-production # Back to development
```
---
## Version Differences
| Feature | V14 | V15 | V16 |
|---------|:---:|:---:|:---:|
| bench init | Yes | Yes | Yes |
| Scheduler tick interval | ~240s | ~240s | **60s** |
| `db_user` config (separate) | No | No | **Yes** |
| `console --autoreload` | No | Yes | Yes |
| `trim-tables` command | No | Yes | Yes |
| `trim-database` command | No | Yes | Yes |
| `request` command | No | Yes | Yes |
| Gettext translations | No | No | **Yes** |
---
## Reference Files
| File | Contents |
|------|----------|
| [commands.md](references/commands.md) | Full command reference with all options |
| [examples.md](references/examples.md) | Common workflow examples |
| [custom-commands.md](references/custom-commands.md) | Creating custom bench CLI commands with Click |
| [anti-patterns.md](references/anti-patterns.md) | Common bench mistakes and fixes |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!