Use this file to discover all available pages before exploring further.
ERPNext is built on top of the Frappe Framework, a full-stack web application framework written in Python and JavaScript. Understanding the architecture is essential for extending and customizing ERPNext.
ERPNext follows a modular, metadata-driven architecture that separates business logic from the framework layer.
1
Application Layer
ERPNext is organized into modules (Accounts, Stock, Selling, Buying, Manufacturing, etc.) that contain business logic and domain-specific functionality.
2
Framework Layer
Frappe Framework provides the foundation: ORM, routing, authentication, background jobs, websockets, and API infrastructure.
3
Database Layer
Uses MariaDB/MySQL with a metadata-driven schema. DocTypes define the data model dynamically.
ERPNext uses JSON metadata files to define DocTypes (data models). The framework reads these definitions and generates database tables, forms, and APIs automatically.
# DocType metadata is stored in JSON files# Example: sales_order.json defines the Sales Order structure{ "doctype": "DocType", "name": "Sales Order", "autoname": "naming_series:", "fields": [ { "fieldname": "customer", "fieldtype": "Link", "options": "Customer", "reqd": 1 } ]}
Role-based permissions are defined in DocType metadata and enforced automatically:
# Check permissions in codeif frappe.has_permission("Sales Order", "write", doc): doc.save()# User permissions filter datafrappe.get_all("Sales Order", filters={"customer": "CUST-001"})# Returns only orders the user has permission to see
from frappe import _def validate(self): # Throw user-friendly error if not self.delivery_date: frappe.throw(_("Delivery Date is mandatory")) # Validation with specific exception type if self.total_qty < 0: frappe.throw( _("Quantity cannot be negative"), exc=InvalidQtyError )