Skip to main content

Implementation cost & partners

ERPNext Custom App Development with Frappe (2026)

How to build a custom Frappe app on ERPNext: DocTypes, server and client scripts, hooks and fixtures, kept upgrade-safe in your own Git repository.

Updated 14 Oct 20269 min readBy ManojFirst published 20 Jul 2026

ERPNext custom app development means building your business logic as a separate Frappe app installed alongside ERPNext, with its own DocTypes, scripts and hooks, instead of editing ERPNext's core files. ERPNext is itself a Frappe app, so yours sits at the same level with the same powers, and an upgrade replaces ERPNext's files without touching it.

Short answer

A custom app is a Python package created with Frappe's bench tool and installed on your ERPNext site. It holds your DocTypes, controllers, hooks and fixtures in one versioned Git repository. Built this way, your logic extends ERPNext without core edits and carries across upgrades, with testing on each major version rather than rework.

ERPNext ships with accounting, stock, manufacturing and CRM (HR is the separate Frappe HR app), but no product fits every business exactly. The question is not whether to extend it but how, and the how decides whether the system stays maintainable or breaks on every update. I am Manoj; I lead ERPNext and Frappe programmes at MithTech, a team of Frappe specialists in Bengaluru, and I have seen both outcomes. When you want it built for you, see custom Frappe app development.

What decides whether an ERPNext system stays healthy is less how much was customised than whether the customisation lives in a proper custom app or was hacked into core.

What is an ERPNext custom app?

A custom app is a standalone Frappe application — a Python package scaffolded with the bench new-app command — installed onto your ERPNext site alongside ERPNext itself. ERPNext is built on the Frappe framework, and ERPNext is technically just one Frappe app among others. Your custom app sits at the same level, with full access to the same APIs, database layer, and UI.

That parity is the point. Your app can define new record types, add fields to ERPNext's DocTypes, run background jobs, expose REST endpoints and react to events, all from its own folder and Git repository. Nothing in ERPNext's source is touched, so an upgrade replaces ERPNext's files and leaves yours alone. For when to configure instead of code, and what drives the cost, see the ERPNext customization guide.

Skimmable summary: A custom app is a separate Frappe app installed beside ERPNext, with equal access to DocTypes, APIs, and events. Your logic lives in your own repository, so ERPNext upgrades leave it untouched.

What are DocTypes and how do they work?

A DocType is Frappe's core building block — a single definition that describes a table's schema, its form layout, its permissions, and its business logic all at once. Every record type you see in ERPNext, from Sales Invoice to Item to Employee, is a DocType. Creating a DocType generates the database table, the form, the list view, and the API automatically.

For custom development there are three ways to shape records:

ApproachWhat it doesWhere it lives
New DocType in your appAdds a record type ERPNext lacks — e.g. "Site Visit", "AMC Contract"Your custom app's module folder
Custom Field on a core DocTypeAdds a field to an existing ERPNext record — e.g. a warranty period on ItemA fixture in your app
Property SetterChanges a property of a core field — label, mandatory, hiddenA fixture in your app

Each DocType can carry a Python controller file — a class with lifecycle methods like validate, before_save, and on_submit — where your rules live. This is where genuine business logic belongs, versioned in your app and reviewable like any other code.

Skimmable summary: DocTypes define a record's schema, form, permissions, and logic in one place. Your app can add brand-new DocTypes, or attach custom fields and property setters to ERPNext's existing ones, each carried as a fixture.

Server scripts vs client scripts — what runs where?

Server scripts are Python that runs on the backend when a document event or an API call fires; client scripts are JavaScript that runs in the user's browser to make the form interactive. The two solve different problems. Server logic enforces rules and touches the database. Client logic reacts to what the user is doing on screen — showing a field, fetching a value, validating before submit.

Script typeLanguageRunsGood for
Server scriptPythonOn the server, on doc events or APIValidation, calculations, enforcing rules, writing data
Client scriptJavaScriptIn the browser formDynamic fields, live totals, UX hints, pre-submit checks
App controller (in code)PythonOn the server, per DocTypeComplex, versioned business logic
hooks.py handlersPythonOn the server, framework-wideReacting to events across DocTypes

Skimmable summary: Server scripts run Python on the backend for validation and data rules; client scripts run JavaScript in the browser for interactive forms. In-desk scripts are quick but live in the database — put real logic in your app's code instead.

How do hooks extend ERPNext without touching core?

Hooks are the central configuration mechanism of a Frappe app, declared in a single hooks.py file that tells Frappe how your app plugs into everything else. Hooks let your app intercept document events, override a DocType's controller class, replace a whitelisted method, inject CSS or JavaScript, and schedule background jobs — all without editing one line of ERPNext's source.

The hooks that matter most in day-to-day custom development:

doc_events

Run your Python function whenever any DocType fires an event — validate, on_submit, on_cancel. This is how you attach cross-cutting rules to ERPNext's own records from outside.

scheduler_events

Register jobs to run hourly, daily, or weekly — nightly syncs, reminders, recalculations. Frappe's scheduler calls your functions on the interval you declare.

fixtures

List the Custom Fields, Property Setters, and other records your app owns so they export to JSON and rebuild on bench migrate.

override methods

Override a DocType's controller class or a whitelisted method to change core behaviour surgically — used sparingly, and always in your app.

Because everything routes through hooks.py, a reviewer can read one file and see every way your app touches ERPNext. That is what keeps a custom app auditable years later.

Skimmable summary: hooks.py is the one file that declares how your app plugs into ERPNext — reacting to document events, scheduling jobs, carrying fixtures, and overriding methods. It extends core behaviour without ever editing core files.

How do you build a custom app on ERPNext?

Building a custom app follows a repeatable path with Frappe's bench tool: scaffold the app, install it on your site, add DocTypes and logic, then export your customisations as fixtures so they travel with the code. The sequence below is the backbone every clean Frappe project follows.

1

Scaffold the app

Run bench new-app your_app to generate the package skeleton — modules, hooks.py, and the folder structure Frappe expects. Initialise it as a Git repository from day one.

2

Install it on the site

Run bench --site yoursite install-app your_app to register the app on your ERPNext site. It now loads alongside ERPNext and can define DocTypes and respond to hooks.

3

Add DocTypes and logic

Create your new DocTypes inside the app, write controller methods for business rules, and wire up doc_events in hooks.py for cross-cutting behaviour. Keep meaningful logic in code, not in-desk scripts.

4

Capture customisations as fixtures

For custom fields and property setters on ERPNext's own DocTypes, list them under fixtures in hooks.py and run bench export-fixtures. This writes them to JSON in your app so they rebuild anywhere.

5

Migrate and test on staging

Run bench migrate to apply everything, then test on a staging copy before it ever reaches production. Staging-first is the habit that catches upgrade surprises early.

If you do not have an in-house developer for this, the guide to hiring an ERPNext developer in India covers what skills to look for.

Skimmable summary: Scaffold with bench new-app, install on your site, add DocTypes and controller logic, export custom fields as fixtures, then migrate and test on staging. Git from day one, staging before production.

How do you keep a custom app upgrade-safe?

Upgrade-safety comes from discipline, not a single setting: keep every customisation inside your app, capture field changes as fixtures, and test on staging before any bench update. The reason matters — a version upgrade overwrites ERPNext's files. Anything you changed in core is lost, and a system built by patching core breaks on every update, which pushes teams to skip updates and end up on unsupported, insecure software.

Three habits keep an app clean. First, prefer fixtures and hooks over in-desk scripts so your logic lives in Git. Second, audit now and then: list every custom field, server script and hook, and delete those whose requirement is gone, because dead customisation is pure upgrade risk. Third, never skip staging; a full bench migrate on a copy of production shows conflicts before your users feel them. Built this way, a major release means testing and small fixes rather than rework, which is what the ERPNext v15 to v16 upgrade asks of a well-structured system.

Skimmable summary: Keep everything in your app, capture field changes as fixtures, audit and delete dead customisations, and always run bench migrate on staging first. Core edits are lost on upgrade — your app is not.

When should you build a custom app instead of configuring?

Reach for a custom app only when configuration genuinely cannot meet the need — a new record type ERPNext does not ship, a scheduled background job, a bespoke integration, an event-driven rule across DocTypes, or logic you want under version control. Most requirements, though, are configuration: custom fields, workflows, print formats, and dashboards need no app and carry no upgrade risk.

Building an app too early is the expensive mistake: it adds maintenance and testing for something the platform could have configured. The test: if it can be a Custom Field, a Workflow or a Property Setter, it should be. Keep the custom app for logic, integrations and record types only code can deliver. What ERPNext covers out of the box is on the Frappe and ERPNext page.

This post is part of the Frappe and ERPNext Architecture Guide. For the choice between a custom field, a custom app and a fork, read custom field, custom app or fork.

Skimmable summary: Build a custom app for new DocTypes, scheduled jobs, integrations, event-driven rules, and versioned logic. For fields, workflows, and print formats, configure instead — coding too early adds cost without benefit.

Frequently asked questions

+

Is ERPNext free to develop custom apps on?

Yes. ERPNext is open source under GPL-3.0, and so is the Frappe framework it runs on. There is no licence fee for extending it and no per-developer charge to build a custom app. You pay for development effort (designing DocTypes, writing logic, testing), not for the right to customise.

+

What is the difference between a custom app and a custom script?

A custom app is a full Python package installed alongside ERPNext, holding DocTypes, controllers, hooks and fixtures in your own Git repository. A custom script (a Server Script or Client Script made in the ERPNext desk) is a small piece of logic stored in the database. Scripts suit one-off tweaks; apps are the home for anything you want versioned, tested and portable.

+

Do custom apps survive ERPNext upgrades?

Yes, when built correctly. A custom app lives in its own files and repository, so an upgrade replaces ERPNext's code and leaves your app alone. A major version can still change APIs your app uses, so test on staging and fix what changed. The real failure is editing ERPNext core: those changes are overwritten on every update.

+

What version of ERPNext should I build on in 2026?

ERPNext v16 is the current major line: v16.0.0 was released on 12 January 2026 (GitHub releases), on Frappe framework v16. New projects in 2026 should generally target v16 for the newest features and the longest support runway. Point releases come often, so check the current one before you start a build.

+

Can a custom app talk to other software?

Yes. Frappe exposes a REST API for every DocType, and your app can add its own whitelisted endpoints, call outside APIs and run scheduled syncs through scheduler_events. Integrations with payment gateways, messaging tools, marketplaces and banks belong in a custom app, where they stay versioned and upgrade-safe.

+

Who owns the custom app that is built for me?

You should. The app and its code belong in a Git repository you own, with the intellectual property assigned to you in the contract, so you can maintain it, extend it or move to another provider at any time. Confirm this in writing before development starts.

Your next step

Need a custom Frappe app built?

Next step · Implementation cost & partners

Now see what ERPNext costs for your business

Implementation, hosting and support for your own modules and team, broken down line by line, with no licence fees in the total.

Comments & ratings

No comments yet. Start a new discussion.

0

Manoj · Published on 20 July 2026

Worked with us? Leave a Google review

Questions about this? Talk to the team.

Book a 30-minute Google Meet, WhatsApp us, or send a message. The engineer who works on this replies.

Send us a message
Your details go to our team's CRM and are used only to reply.