Skip to content

Development Environment

Before you can write a line of Frappe code, you need a running bench. Coming from Node.js, think of this as the moment you’d npm install and npm run dev — except Frappe pulls in a database, a cache, a queue, and a realtime server, so the setup is heavier. This chapter walks through getting a Frappe v16 + ERPNext bench up, either natively on Ubuntu or inside a Docker DevContainer, plus the editor wiring and the failures you’ll actually hit.

Frappe v16 expects a specific set of system dependencies. Get these versions right up front — most setup failures trace back to a stale Python or Node.

DependencyRequired VersionWhy
Python3.14+Frappe v16 server-side runtime
Node.js24 LTSAsset building (esbuild) + Socket.IO
MariaDB10.6+Primary database (or Postgres 14+)
Redis8+Caching, queues, real-time messaging
Git2.xApp management, version control
pipLatestPython package installer
wkhtmltopdf0.12.6+PDF generation (legacy; v16 adds Chrome)
Yarn1.xNode.js dependency management

There are two practical ways to run a dev bench. Native bench installs everything directly on the host OS — best for production servers and developers who want full control. Docker uses the official frappe_docker DevContainer and sidesteps the “works on my machine” problem entirely. Pick one; the tabs below stay in sync across the page.

The bare-metal approach on Ubuntu 24.04. You install Python, Node, MariaDB, Redis, and bench directly, then initialize a bench and a site.

  1. Install system dependencies.

    Terminal window
    sudo apt update && sudo apt upgrade -y
    # Install core dependencies
    sudo apt install -y \
    git \
    python3-dev \
    python3-pip \
    python3-venv \
    python3-setuptools \
    build-essential \
    libffi-dev \
    libssl-dev \
    libjpeg-dev \
    libpng-dev \
    zlib1g-dev \
    libmysqlclient-dev \
    curl \
    wget \
    software-properties-common
  2. Install Python 3.14. Ubuntu 24.04 ships with Python 3.12 — you need 3.14 for Frappe v16.

    Terminal window
    # Add deadsnakes PPA for newer Python versions
    sudo add-apt-repository ppa:deadsnakes/ppa -y
    sudo apt update
    # Install Python 3.14
    sudo apt install -y python3.14 python3.14-dev python3.14-venv
    # Verify
    python3.14 --version
    # Expected output: Python 3.14.x
  3. Install Node.js 24.

    Terminal window
    # Install Node.js 24 via NodeSource
    curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
    sudo apt install -y nodejs
    # Verify
    node --version
    # Expected output: v24.x.x
    npm --version
    # Expected output: 10.x.x
    # Install Yarn globally
    sudo npm install -g yarn
  4. Install and configure MariaDB. The utf8mb4 character-set config is mandatory.

    Terminal window
    sudo apt install -y mariadb-server mariadb-client
    # Secure the installation
    sudo mysql_secure_installation
    # Switch to unix_socket auth? N
    # Change root password? Y (set a strong password)
    # Remove anonymous users? Y
    # Disallow root login remotely? Y
    # Remove test database? Y
    # Reload privilege tables? Y
    /etc/mysql/mariadb.conf.d/99-frappe.cnf
    [mysqld]
    character-set-client-handshake = FALSE
    character-set-server = utf8mb4
    collation-server = utf8mb4_unicode_ci
    [mysql]
    default-character-set = utf8mb4
    Terminal window
    sudo systemctl restart mariadb
    # Verify
    mariadb --version
    # Expected output: mariadb Ver 15.x Distrib 10.x.x-MariaDB
  5. Install Redis.

    Terminal window
    sudo apt install -y redis-server
    # Verify
    redis-server --version
    # Expected output: Redis server v=8.x.x ...
    sudo systemctl enable redis-server
    sudo systemctl start redis-server
  6. Install wkhtmltopdf.

    Terminal window
    # Download and install the patched Qt version
    wget https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.jammy_amd64.deb
    sudo dpkg -i wkhtmltox_0.12.6.1-3.jammy_amd64.deb
    sudo apt install -f -y # Fix any dependency issues
    # Verify
    wkhtmltopdf --version
    # Expected output: wkhtmltopdf 0.12.6.1 (with patched qt)
  7. Install bench.

    Terminal window
    # Install bench CLI
    pip install frappe-bench
    # Verify
    bench --version
    # Expected output: 5.x.x
  8. Initialize a new bench with Frappe v16, from your home directory.

    Terminal window
    bench init frappe-bench --frappe-branch version-16 --python python3.14
    # Getting frappe
    # shallow clone https://github.com/frappe/frappe.git --branch version-16 --depth 1
    # Setting Up Environment / Procfile / Redis
    # SUCCESS: Bench frappe-bench initialized
    cd frappe-bench
  9. Create a site.

    Terminal window
    # Replace <your-mariadb-root-password> with the password you set earlier
    bench new-site icecream.localhost --mariadb-root-password <your-mariadb-root-password>
    # Installing frappe...
    # Updating DocTypes for frappe: [========================================] 100%
    # Site icecream.localhost created successfully.
    # Set it as the default site
    bench use icecream.localhost
  10. Install ERPNext on the site.

    Terminal window
    # Download the ERPNext app
    bench get-app erpnext --branch version-16
    # Install ERPNext on your site
    bench --site icecream.localhost install-app erpnext
    # Installing erpnext...
    # Updating DocTypes for erpnext: [========================================] 100%
  11. Start the development server.

    Terminal window
    bench start
    # 14:30:00 web.1 | * Running on http://0.0.0.0:8000
    # 14:30:00 socketio.1 | listening on port 9000
    # 14:30:00 watch.1 | watching for file changes...
    # 14:30:01 worker.1 | Worker rq:worker started
    # 14:30:01 schedule.1 | Scheduler started

Open your browser to http://icecream.localhost:8000 and log in:

  • Username: Administrator
  • Password: the password you set during bench new-site (or admin if you did not specify one)

Cloud-based environments (Gitpod / Codespaces)

Section titled “Cloud-based environments (Gitpod / Codespaces)”

For zero-local-setup development — workshops, demos, quick experiments — use a cloud environment that builds the same DevContainer in the cloud.

Gitpod reads the .gitpod.yml in the repo and provisions a full environment when you open this URL (swap in your fork if needed):

https://gitpod.io/#https://github.com/frappe/frappe_docker

GitHub Codespaces:

  1. Fork frappe/frappe_docker on GitHub.
  2. Click the green “Code” button, the Codespaces tab, then “Create codespace on main”.
  3. The devcontainer configuration is picked up automatically.
  4. Follow the same bench init steps as the Docker method above.

A little editor wiring makes Frappe far more pleasant — Python autocomplete across apps, and step-through debugging of the request cycle. Drop these files into your bench directory.

The recommended extensions cover Python, ESLint/Prettier for client scripts, the DevContainers extension, and Jinja highlighting for print formats:

~/frappe-bench/.vscode/extensions.json
{
"recommendations": [
"ms-python.python",
"ms-python.debugpy",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-vscode-remote.remote-containers",
"samuelcolvin.jinjahtml"
]
}

The debug config launches the Frappe web server (and a worker) under debugpy so you can set breakpoints and inspect the stack. Note the --noreload flag — the auto-reloader and the debugger don’t coexist.

~/frappe-bench/.vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Frappe Web",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/apps/frappe/frappe/utils/bench_helper.py",
"args": ["frappe", "serve", "--port", "8000", "--noreload"],
"env": {
"DEV_SERVER": "1"
},
"cwd": "${workspaceFolder}/sites",
"python": "${workspaceFolder}/env/bin/python"
},
{
"name": "Frappe Worker (short)",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/apps/frappe/frappe/utils/bench_helper.py",
"args": ["frappe", "worker", "--queue", "short"],
"cwd": "${workspaceFolder}/sites",
"python": "${workspaceFolder}/env/bin/python"
}
]
}

To debug:

  1. Stop bench start if it’s running (it would hold port 8000).
  2. Set breakpoints in your Python code.
  3. Press F5 to start the Frappe Web configuration.
  4. Trigger the code path from the browser.
  5. VS Code hits your breakpoint with full stack inspection.

Finally, point VS Code’s Python tooling at the bench virtualenv and the app source so imports resolve:

~/frappe-bench/.vscode/settings.json
{
"python.defaultInterpreterPath": "./env/bin/python",
"python.analysis.extraPaths": [
"./apps/frappe",
"./apps/erpnext",
"./apps/scoopjoy"
],
"[python]": {
"editor.defaultFormatter": "ms-python.python"
}
}

bench new-site fails with “Access denied for user ‘root’@‘localhost’”

Section titled “bench new-site fails with “Access denied for user ‘root’@‘localhost’””

Grant root access via socket auth, then set a password:

Terminal window
sudo mariadb -u root
ALTER USER 'root'@'localhost' IDENTIFIED BY 'your_new_password';
FLUSH PRIVILEGES;
EXIT;

Then retry with bench new-site icecream.localhost --mariadb-root-password your_new_password.

Terminal window
# Check current Node version
node --version
# If it's not v24.x, remove the old version and install Node 24
sudo apt remove -y nodejs
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs
Terminal window
# Verify Redis is running
sudo systemctl status redis-server
# If not running
sudo systemctl start redis-server
sudo systemctl enable redis-server
# Check Redis is listening
redis-cli ping
# Expected output: PONG

Site does not load in the browser (DNS resolution)

Section titled “Site does not load in the browser (DNS resolution)”
Terminal window
# For *.localhost domains, add to /etc/hosts
echo "127.0.0.1 icecream.localhost" | sudo tee -a /etc/hosts
# Or hit 127.0.0.1:8000 directly, after setting the default site:
bench use icecream.localhost
Terminal window
# Explicitly specify the Python executable
bench init frappe-bench --frappe-branch version-16 --python python3.14
# If python3.14 is not in PATH, use the full path
bench init frappe-bench --frappe-branch version-16 --python /usr/bin/python3.14
Terminal window
# Use --user flag
pip install --user frappe-bench
# Or create a dedicated venv
python3.14 -m venv ~/bench-env
source ~/bench-env/bin/activate
pip install frappe-bench

With a bench running, you’re ready to drive it. The next chapter is a tour of the bench CLI — the single command you’ll live inside for the rest of this course.