Stackvora.tech

Customising ERPNext safely: DocTypes, custom fields and server scripts

When to use Customize Form, custom apps, client scripts or server scripts in ERPNext — and how to keep your changes upgrade-safe.

ERPNext gives you at least five ways to change behaviour. Picking the right one decides whether your next bench update is uneventful.

The customisation ladder

  1. Customize Form — add custom fields, change labels, defaults, hide fields. Stored as Property Setters and Custom Fields; fully upgrade-safe.
  2. Client Script — JavaScript running in the form, for dynamic UI and validation feedback.
  3. Server Script — sandboxed Python for document events, scheduled jobs and API endpoints. No filesystem access, no arbitrary imports.
  4. Custom App — a proper Frappe app with hooks, new DocTypes, tests and version control. The right answer for anything substantial.
  5. Core edits — never. They are overwritten on update.

Example: validation with a server script

# Server Script, type: DocType Event, DocType: Sales Order, Event: Before Save
if doc.grand_total > 100000 and not doc.custom_approved_by:
    frappe.throw("Orders above 100,000 require an approver.")

Example: client script for UX

frappe.ui.form.on('Sales Order', {
  customer(frm) {
    if (!frm.doc.customer) return;
    frappe.db.get_value('Customer', frm.doc.customer, 'custom_credit_hold')
      .then(r => {
        if (r.message.custom_credit_hold) {
          frm.dashboard.set_headline_alert('Customer is on credit hold');
        }
      });
  }
});

Custom app hooks

In a custom app, wire events declaratively in hooks.py so they are versioned with your code:

doc_events = {
    "Sales Order": {
        "on_submit": "my_app.sales.hooks.notify_warehouse",
        "validate": "my_app.sales.hooks.check_credit",
    }
}
scheduler_events = {
    "daily": ["my_app.tasks.expire_quotations"],
}

Rules that keep upgrades boring

  • Prefix every custom field with custom_ — ERPNext v15+ does this automatically and it prevents collisions with future core fields.
  • Export your customisations (bench --site x export-fixtures) into a custom app so they travel between environments.
  • Never modify standard DocTypes in Developer Mode on production.
  • Write tests for server-side logic; bench --site x run-tests --app my_app in CI catches most upgrade breakage.
  • Read the release notes for renamed fields before upgrading a major version.

Reporting

Use Query Reports (SQL) for read-only analysis and Script Reports for computed columns. Both live in a custom app when they matter, so they are reviewable and deployable rather than clicked into production.

Back to the knowledge base · Ask the AI assistant