The Bench CLI
What is Bench?
Section titled “What is Bench?”Bench is the command-line tool that orchestrates your entire Frappe ecosystem. It
manages sites, apps, database operations, background workers, deployments, and
more. Think of it as docker compose + npm + django-admin rolled into one —
purpose-built for Frappe.
Every Frappe operation goes through bench. You never interact with Gunicorn, Redis, or MariaDB directly in day-to-day development.
# See all available commandsbench --help
# Output (truncated):# Usage: bench [OPTIONS] COMMAND [ARGS]...## Commands:# backup Backup site# build Build JS and CSS assets# clear-cache Clear cache, doctype cache, and defaults# console Start interactive Python console for a site# disable-scheduler Disable scheduler# doctor Diagnose scheduler and worker health# drop-site Remove a site completely# enable-scheduler Enable scheduler# execute Execute a function# export-csv Export DocType data as CSV# get-app Clone and install a Frappe app# init Initialize a new bench instance# install-app Install app on a site# migrate Run database migrations and patches# new-app Create a new Frappe app scaffold# new-site Create a new site# pip Run pip in bench virtualenv# remove-app Remove app from bench# restart Restart production services# restore Restore site from backup# run-tests Run test suite# set-config Set site or common config values# setup Setup utilities (production, nginx, etc.)# start Start development server# switch-to-branch Switch app to a different branch# update Pull latest changes and update bench# use Set default site# version Show versions of all installed apps# watch Watch and rebuild assets on changes# ...Site management
Section titled “Site management”A site is a tenant with its own database and files. These commands create, switch between, configure, and remove sites on the bench.
Creating sites
Section titled “Creating sites”# Basic site creationbench new-site icecream.localhost --mariadb-root-password mypassword
# With specific admin passwordbench new-site icecream.localhost \ --mariadb-root-password mypassword \ --admin-password SecurePass123
# With a specific database namebench new-site icecream.localhost \ --mariadb-root-password mypassword \ --db-name icecream_db
# Using Postgres instead of MariaDBbench new-site icecream.localhost \ --db-type postgres \ --db-host localhost \ --db-port 5432Switching and managing sites
Section titled “Switching and managing sites”# Set the default site (used when --site is omitted)bench use icecream.localhost
# List all sitesls sites/*/site_config.json# Output:# sites/icecream.localhost/site_config.json# sites/franchise-hq.localhost/site_config.json
# Set a configuration value for a sitebench --site icecream.localhost set-config key value
# Set a configuration value for all sites (common config)bench set-config -g key value
# View site configcat sites/icecream.localhost/site_config.jsonRemoving sites
Section titled “Removing sites”# Drop a site (removes database, files, and site directory)bench drop-site test-site.localhost --mariadb-root-password mypassword
# Force drop without confirmationbench drop-site test-site.localhost --force --mariadb-root-password mypasswordRunning migrations
Section titled “Running migrations”bench migrate is how schema changes reach the database — it reads your DocType
JSON, alters tables, runs patches, and rebuilds the search index. There are no
hand-written migration files.
# Migrate a specific site (applies schema changes, patches, rebuilds search)bench --site icecream.localhost migrate
# Migrate all sites on the benchbench --site all migrate
# Expected output:# Migrating icecream.localhost# Updating DocTypes for frappe: [========================================] 100%# Updating DocTypes for erpnext: [========================================] 100%# Running patches...# Updating Dashboard...App management
Section titled “App management”Apps are the Python/JavaScript packages installed on a bench. These commands fetch them, scaffold new ones, and install or remove them per site.
Getting apps
Section titled “Getting apps”# Get an app from GitHub (specific branch)bench get-app erpnext --branch version-16
# Get an app from a custom repositorybench get-app https://github.com/your-org/ice_cream_shop.git --branch main
# Get an app from a local pathbench get-app /path/to/local/ice_cream_shopCreating a new app
Section titled “Creating a new app”bench new-app ice_cream_shop
# Interactive prompts:# App Title (default: Ice Cream Shop): Ice Cream Shop# App Description: Custom app for franchise ice cream business management# App Publisher: Your Name# App Email: dev@icecreamshop.com# App License (default: MIT): MIT
# Expected output:# App ice_cream_shop created at apps/ice_cream_shopThis creates the following scaffold:
Directoryapps/ice_cream_shop/
Directoryice_cream_shop/
- __init__.py
- hooks.py app configuration and event hooks
- patches.txt database migration patches
- modules.txt list of modules in this app
Directorytemplates/
- __init__.py
Directoryice_cream_shop/ default module (same name as app)
- __init__.py
Directorypublic/ static assets (JS, CSS, images)
- …
Directorywww/ website pages
- …
- setup.py
- pyproject.toml
- requirements.txt
- license.txt
- README.md
Installing and removing apps
Section titled “Installing and removing apps”# Install an app on a specific sitebench --site icecream.localhost install-app ice_cream_shop
# Remove an app from a sitebench --site icecream.localhost remove-app ice_cream_shop
# Completely remove an app from the bench (uninstalls from all sites first)bench remove-app ice_cream_shopDevelopment commands
Section titled “Development commands”Starting the development server
Section titled “Starting the development server”# Start all development processes (web, socketio, redis, workers, watch)bench start
# This reads the Procfile and starts:# web: bench serve --port 8000# socketio: /usr/bin/node apps/frappe/socketio.js# watch: bench watch# schedule: bench schedule# worker: bench worker --queue short,default,longbench start is a convenience wrapper that launches all processes defined in the
Procfile. Press Ctrl+C to stop all processes.
Building assets
Section titled “Building assets”# Build all JS and CSS assets for all appsbench build
# Build assets for a specific app onlybench build --app ice_cream_shop
# Expected output:# Building ice_cream_shop...# DONE in 2.34s
# Watch for file changes and rebuild automaticallybench watch
# This is already included in `bench start`, but useful# if you are running the web server separately via VS Code debuggerClearing caches
Section titled “Clearing caches”# Clear all caches (Redis + local)bench --site icecream.localhost clear-cache
# Clear website-specific cache (template cache, page cache)bench --site icecream.localhost clear-website-cache
# When to clear cache:# - After modifying hooks.py# - After changing DocType definitions manually# - When the UI shows stale data after code changes# - After switching branchesConsole and debugging
Section titled “Console and debugging”Interactive Python console
Section titled “Interactive Python console”The console is your most-used debugging tool. Where in a Node.js project you might
drop into node with your app required in, here you get an IPython REPL with the
full Frappe context already wired up.
# Open a Python console with Frappe context loaded for a sitebench --site icecream.localhost console
# Inside the console:# In [1]: frappe.get_doc("User", "Administrator")# Out[1]: <frappe.core.doctype.user.user.User object at 0x...>## In [2]: frappe.db.sql("SELECT name, email FROM tabUser LIMIT 5")# Out[2]: (('Administrator', 'admin@example.com'), ('Guest', 'guest@example.com'))## In [3]: frappe.db.count("Sales Invoice")# Out[3]: 42## In [4]: doc = frappe.get_doc({# "doctype": "Ice Cream Flavor",# "flavor_name": "Mango Alphonso",# "base_type": "Sorbet",# "cost_per_scoop": 45.00# })# In [5]: doc.insert()# In [6]: frappe.db.commit()The console is an IPython REPL with the full Frappe context — database connection, session, caching — all wired up. This is your go-to tool for exploring data, testing queries, and debugging.
Executing functions directly
Section titled “Executing functions directly”# Execute any Python function in the Frappe contextbench --site icecream.localhost execute frappe.client.get_count \ --args '["Sales Invoice"]'
# Execute a function from your custom appbench --site icecream.localhost execute \ ice_cream_shop.tasks.sync_franchise_inventory \ --kwargs '{"franchise_id": "FRAN-001"}'Running tests
Section titled “Running tests”# Run all tests for an appbench --site icecream.localhost run-tests --app ice_cream_shop
# Run tests for a specific DocTypebench --site icecream.localhost run-tests \ --doctype "Ice Cream Flavor"
# Run a specific test filebench --site icecream.localhost run-tests \ --module ice_cream_shop.ice_cream_shop.doctype.ice_cream_flavor.test_ice_cream_flavor
# Run with verbose outputbench --site icecream.localhost run-tests --app ice_cream_shop -v
# Expected output:# Running tests for ice_cream_shop# .....# Ran 5 tests in 3.456s# OKDirect database access
Section titled “Direct database access”# Open a MariaDB shell for the site's databasebench --site icecream.localhost mariadb
# MariaDB [icecream_db]> SHOW TABLES LIKE '%flavor%';# +-----------------------------------+# | Tables_in_icecream_db (%flavor%) |# +-----------------------------------+# | tabIce Cream Flavor |# +-----------------------------------+## MariaDB [icecream_db]> SELECT name, base_type, cost_per_scoop# FROM `tabIce Cream Flavor` LIMIT 5;Backup and restore
Section titled “Backup and restore”Creating backups
Section titled “Creating backups”# Basic database backupbench --site icecream.localhost backup
# Expected output:# Backup for site icecream.localhost:# Database: ~/frappe-bench/sites/icecream.localhost/private/backups/# 20260320_143000-icecream_localhost-database.sql.gz
# Full backup with public and private filesbench --site icecream.localhost backup --with-files
# Expected output:# Database: .../20260320_143000-icecream_localhost-database.sql.gz# Private: .../20260320_143000-icecream_localhost-private-files.tar# Public: .../20260320_143000-icecream_localhost-files.tar
# Backup to a specific path with compressionbench --site icecream.localhost backup \ --with-files \ --compress \ --backup-path /tmp/backups/
# Backup all sitesbench --site all backup --with-filesRestoring from backup
Section titled “Restoring from backup”# Restore database onlybench --site icecream.localhost restore \ /path/to/20260320_143000-icecream_localhost-database.sql.gz
# Restore with filesbench --site icecream.localhost restore \ /path/to/20260320_143000-icecream_localhost-database.sql.gz \ --with-private-files /path/to/20260320_143000-icecream_localhost-private-files.tar \ --with-public-files /path/to/20260320_143000-icecream_localhost-files.tar
# After restoring, always migratebench --site icecream.localhost migrateProduction setup
Section titled “Production setup”Setting up for production
Section titled “Setting up for production”These commands generate the Nginx and Supervisor configs that turn a dev bench into a managed production deployment.
# Generate Nginx and Supervisor configuration, set up productionsudo bench setup production <your-linux-username>
# This command:# 1. Generates /etc/nginx/conf.d/frappe-bench.conf# 2. Generates /etc/supervisor/conf.d/frappe-bench.conf# 3. Enables and starts Supervisor and Nginx# 4. Enables the scheduler
# If you need to regenerate configs after changes:sudo bench setup nginxsudo bench setup supervisor
# Restart production servicessudo bench restartNginx and SSL
Section titled “Nginx and SSL”# Set up Let's Encrypt SSL for a sitesudo bench setup lets-encrypt icecream.example.com
# For multi-tenant setups with wildcard SSLsudo bench setup wildcard-ssl example.comScheduler management
Section titled “Scheduler management”The scheduler runs the periodic jobs defined in your app’s hooks.py. It must be
enabled for background jobs to fire in production.
# Enable the scheduler (required for background jobs in production)bench --site icecream.localhost enable-scheduler
# Disable the scheduler (useful during maintenance)bench --site icecream.localhost disable-scheduler
# Check the health of scheduler and workersbench doctor
# Expected output:# -----Checking scheduler status-----# icecream.localhost: Active## -----Checking worker status-----# Workers online: 3# -----active_jobs-----# No active jobs# -----queued_jobs-----# No queued jobsMulti-tenancy
Section titled “Multi-tenancy”Frappe supports hosting multiple sites on a single bench, accessible via different domain names. This is how a single bench can serve every ScoopJoy franchise from one codebase.
# Enable DNS-based multi-tenancybench config dns_multitenant on
# Create additional sitesbench new-site franchise-north.example.com --mariadb-root-password mypasswordbench new-site franchise-south.example.com --mariadb-root-password mypassword
# Install apps on each sitebench --site franchise-north.example.com install-app erpnextbench --site franchise-north.example.com install-app ice_cream_shop
# Add a custom domain to a sitebench setup add-domain franchise-north.example.com --site franchise-north.example.com
# Regenerate Nginx config to include the new sitesbench setup nginxsudo service nginx reloadVersion management
Section titled “Version management”Updating your bench
Section titled “Updating your bench”# Full update: pulls code, installs requirements, builds, migrates, restartsbench update
# Update without restarting (useful during development)bench update --no-restart
# Only pull code without migratingbench update --pull
# Update a specific app onlybench update --apps erpnext
# Reset to upstream code (discards local changes -- use with caution)bench update --resetSwitching branches
Section titled “Switching branches”# Switch an app to a different branchbench switch-to-branch version-16 frappe erpnext
# Switch only ERPNext to develop branchbench switch-to-branch develop erpnext
# After switching branches, always migratebench --site icecream.localhost migratePractical workflow: from zero to running custom app
Section titled “Practical workflow: from zero to running custom app”Here is a complete, end-to-end workflow that ties all the bench commands together. This is the sequence you will follow for every new project — and it reuses the native install from Development Environment Setup.
# 1. Initialize a new benchbench init ice-cream-bench --frappe-branch version-16 --python python3.14cd ice-cream-bench
# 2. Create a sitebench new-site icecream.localhost --mariadb-root-password mypassword --admin-password admin123bench use icecream.localhost
# 3. Get and install ERPNextbench get-app erpnext --branch version-16bench --site icecream.localhost install-app erpnext
# 4. Create your custom appbench new-app ice_cream_shopbench --site icecream.localhost install-app ice_cream_shop
# 5. Start developingbench start# (Open http://icecream.localhost:8000 in your browser)
# 6. After making code changes, build and testbench build --app ice_cream_shopbench --site icecream.localhost run-tests --app ice_cream_shop
# 7. When you modify DocTypes, migratebench --site icecream.localhost migrate
# 8. Before calling it a day, back upbench --site icecream.localhost backup --with-files
# 9. Clear cache if anything looks stalebench --site icecream.localhost clear-cache
# 10. Check system healthbench doctorQuick reference: most-used commands
Section titled “Quick reference: most-used commands”| Command | Purpose |
|---|---|
bench start | Start dev server |
bench new-site <name> | Create a new site |
bench use <name> | Set default site |
bench get-app <url/name> | Download an app |
bench --site <name> install-app <app> | Install app on site |
bench new-app <name> | Scaffold a new app |
bench --site <name> migrate | Run migrations and patches |
bench --site <name> clear-cache | Clear all caches |
bench build | Build JS/CSS assets |
bench --site <name> console | Python REPL with Frappe context |
bench --site <name> backup --with-files | Full backup |
bench --site <name> restore <file> | Restore from backup |
bench --site <name> mariadb | Open database shell |
bench --site <name> run-tests --app <app> | Run tests |
bench doctor | Check scheduler and worker health |
bench update | Pull, build, migrate, restart |
bench --site <name> set-config <k> <v> | Set site config value |
bench execute <dotted.path> | Run a Python function |