If you’ve installed ERPNext yourself, you’ve already met bench. It’s the first thing you install and the tool you’ll type most often afterwards. The Frappe docs are careful about one ambiguity: “bench” can mean the CLI you run or the directory it manages. In conversation people use both, and the context usually tells you which.
The directory
bench init creates a folder with a fixed layout. Everything a Frappe deployment needs lives inside it:
frappe-bench/
├── apps/ # frappe, erpnext, your own apps (Git repos)
├── sites/
│ ├── apps.txt # apps available on this bench
│ ├── assets/ # built JS and CSS
│ ├── common_site_config.json
│ └── erp.example.com/
│ ├── site_config.json
│ ├── private/
│ └── public/
├── config/ # Redis, NGINX and supervisor config
├── env/ # Python virtual environment
├── logs/
└── Procfile # processes started by bench start
The split between apps and sites is the idea to hold on to. Code lives once in apps, and each folder in sites is a separate database and config that can have any of those apps installed. One bench can serve several companies’ sites from the same code.
Configuration follows the same split. common_site_config.json applies to every site on the bench, and each site’s own site_config.json holds its database credentials and anything specific to it. bench --site erp.example.com set-config key value writes to the site file, while adding -g writes to the common one. When a setting seems to be ignored, check both files before anything else.
Commands you’ll use every week
The CLI itself is installed from PyPI as frappe-bench. A typical first setup, then the day-to-day commands:
bench init --frappe-branch version-15 frappe-bench
cd frappe-bench
bench new-site erp.example.com
bench get-app --branch version-15 erpnext
bench --site erp.example.com install-app erpnext
bench start # development server
bench --site erp.example.com migrate # patches, schema sync, fixtures
bench --site erp.example.com backup
bench --site erp.example.com console # IPython with the site loaded
bench --site erp.example.com clear-cache
bench build --app my_app
Swap version-15 for version-16 on a v16 bench. The site commands need --site unless you’ve set a default with bench use erp.example.com.
Two sets of commands behind one name
Not every bench command comes from the bench package. init, get-app, update, setup production and restart belong to the CLI. Site-level commands such as new-site, install-app, migrate, console and export-fixtures are defined by the Frappe Framework, and bench passes them through. That’s why a site command can behave differently between v15 and v16 while your bench CLI version stays the same. When a flag isn’t doing what you expect, check the Frappe version first.
Mistakes that cost an afternoon
Editing code inside apps/erpnext or apps/frappe. bench update refuses to pull while an app has uncommitted changes, and bench update --reset fixes that by running git reset --hard, wiping your edits. Put changes in your own Frappe app instead. erpfly never touches those two folders; everything it generates goes into a separate app you install with install-app.
Migrating production without a backup. migrate runs patches that change data. Take a backup first, even though bench update takes one for you, because you’ll often run migrate on its own. Our notes on keeping customizations through an ERPNext upgrade walk through a safer order.
Developer mode on a live site. bench set-config -g developer_mode 1 is right for a development bench and wrong for production, where DocTypes should arrive through migrate, not be created by hand.
Forgetting that a change to hooks.py may need migrate and a restart before the running workers see it.