# Frappe app (ERPNext glossary)

Canonical: https://erpfly.com/glossary/frappe-app/
Last updated: September 14, 2026

**Definition:** A Frappe app is a Python package built on the Frappe Framework that lives in a bench's apps folder and gets installed on one or more sites. ERPNext is itself a Frappe app, and a custom Frappe app holds your own DocTypes, hooks, patches and front-end assets in a Git repository.

Also called: Frappe custom app, custom Frappe app, Frappe application, ERPNext custom app

Frappe itself is an app. So is ERPNext, and so are HRMS, Helpdesk and the rest of the official catalogue. When we say "put it in a custom app", we mean the same kind of package, only it's yours: it sits next to `frappe` and `erpnext` in the `apps` folder of your bench, and nothing in it gets overwritten when those two are updated.

### What's inside the folder

`bench new-app` generates the skeleton. On v15 and v16 it looks roughly like this:

```text
apps/acme_custom/
├── pyproject.toml          # package metadata and Python dependencies
├── license.txt
├── README.md
└── acme_custom/
    ├── __init__.py         # holds __version__
    ├── hooks.py
    ├── modules.txt
    ├── patches.txt
    ├── acme_custom/        # the first module, named after the app title
    ├── config/
    ├── patches/
    ├── public/             # served at /assets/acme_custom/
    ├── templates/
    └── www/                # portal pages
```

The file that matters most is hooks.py, which tells Frappe how the app plugs into document events, scheduled jobs and other apps. `modules.txt` lists the app's modules, and every DocType belongs to one of them. `patches.txt` lists data migrations, split into `[pre_model_sync]` and `[post_model_sync]` sections depending on whether they run before or after DocType schemas are synced. Older apps you inherit may still use `setup.py` and `requirements.txt` in place of `pyproject.toml`.

### Getting it onto a site

Creating an app and installing it are separate steps. The app lives on the bench; installing it on a site creates its tables in that site's database.

```bash
cd ~/frappe-bench
bench new-app acme_custom
bench --site erp.example.com install-app acme_custom
bench --site erp.example.com list-apps

# on another bench, pull it from your Git remote instead
bench get-app https://github.com/acme/acme_custom --branch main
bench --site erp.example.com install-app acme_custom
```

If the app depends on ERPNext, say so with `required_apps = ["erpnext"]` in `hooks.py`. Frappe then installs ERPNext on the site before your app, and refuses to uninstall ERPNext while your app still needs it. Be careful with `uninstall-app`. It removes the app's data from the site, not only its code.

### Why we default to a custom app

Anything created through the desk without an app lives in one site's database. You can't diff it, test it or review it. With an app, DocTypes are JSON files, controllers are Python, fixtures carry your Custom Fields, and `bench migrate` brings any site up to date. That's the setup erpfly generates: a Frappe app delivered as a pull request, with no edits to the `frappe` or `erpnext` folders. Our page on [ERPNext custom module development](https://erpfly.com/erpnext-custom-module-development/) goes through what usually goes into one.

An app isn't always worth it. For a one-line validation you need today, on a site where you can't deploy code quickly, a Server Script is the practical choice. We compare the two in detail in [Server Scripts vs a custom app](https://erpfly.com/blog/server-scripts-vs-custom-app-erpnext/).

### Apps, modules and sites

People mix these three up. A **site** is one database with its own config, users and data. An **app** is code on the bench that you install on sites, where the same app can serve many sites. A **module** is a grouping inside an app, used to organise DocTypes, reports and pages. When hooks from two installed apps clash, Frappe gives priority to the app installed last on that site, which is worth remembering when two custom apps both override the same DocType class.

See also: https://erpfly.com/glossary/bench/, https://erpfly.com/glossary/hooks-py/, https://erpfly.com/glossary/doctype/, https://erpfly.com/glossary/fixtures/, https://erpfly.com/glossary/server-script/

### Sources

- [Apps, Frappe Framework documentation](https://docs.frappe.io/framework/user/en/basics/apps)
- [frappe/utils/boilerplate.py (version-15), frappe/frappe on GitHub](https://github.com/frappe/frappe/blob/version-15/frappe/utils/boilerplate.py)
- [Hooks, Frappe Framework documentation](https://docs.frappe.io/framework/user/en/python-api/hooks)