How to Create a DocType in Frappe Framework (Version 15)
Introduction — Understanding DocTypes in Frappe
A DocType in the Frappe Framework defines the structure of a database table and the form interface users interact with.
It acts as the core data model in Frappe — everything from Customers, Invoices, or Employees to custom business objects are implemented as DocTypes.
Each DocType:
- Represents a database table in MariaDB.
- Defines fields, permissions, and behavior.
- Can include logic through custom scripts, server scripts, or controller files.In Frappe v15, DocType creation has been made even more streamlined through improved Desk UI and simplified developer workflows.
Prerequisites for Creating a DocType in Frappe v15
Before creating a DocType, ensure the following setup is complete.
Environment Requirements
- Frappe Framework: Version 15 (installed and running)
- Bench CLI: Installed globally (pip install frappe-bench)
- App Context: A Frappe app (e.g., my_app) where your DocType will reside
- User Role: Developer access with permission to create new DocTypes
If you haven’t created an app yet:
bench new-app my_app
Then install it on your site:
bench --site site-name.localhost install-app my_app
Step-by-Step Guide — How to Create a DocType in Frappe
Creating a DocType can be done directly through the Desk UI or the command line.
Below are both approaches as per Frappe Framework v15 best practices.
Option 1: Create a DocType from the Frappe Desk
- Login to your Frappe site (e.g., http://site-name.localhost:8000).
- In the search bar, type and open “DocType List”.
- Click “New” to create a new DocType.
You’ll see a form with multiple fields. Fill them as follows:
|
Field |
Description |
|
Name |
The name of your DocType (e.g., “Task Tracker”) |
| Module |
Select the module under your app (e.g., “Projects”) |
|
Custom? |
Leave unchecked for standard DocTypes (checked for Custom DocTypes) |
|
Is Submittable? |
Enable if the document supports submission workflow |
|
Fields Table |
Define the fields your DocType will contain (Fieldname, Label, Type, etc.) |
| Permissions Table |
Configure which roles can read/write/create this document |
After entering details, Save and Reload.
Frappe automatically generates:
- A corresponding database table (tabTask Tracker)
- JSON and Python controller files in your app directory
Option 2: Create a DocType via Bench CLI
If you prefer working from the terminal, you can create a DocType using Bench.
Navigate to your app directory and run:
cd frappe-bench/apps/my_app
bench make-doctype "Task Tracker"
This automatically:
- Creates the DocType folder inside my_app/my_app/doctype/
- Adds:
- task_tracker.json (DocType schema)
- task_tracker.py (controller file)
- task_tracker.js (client script placeholder)
- __init__.py file for module imports
Example:
my_app/
└── my_app/
└── doctype/
└── task_tracker/
├── __init__.py
├── task_tracker.json
├── task_tracker.py
└── task_tracker.js
Example: Creating a “Task Tracker” DocType
Let’s create a simple Task Tracker DocType to manage project tasks.
Step 1: Run the Command
bench make-doctype "Task Tracker" --module "Projects"
Step 2: Define Fields in the JSON Schema
Open the generated file:
my_app/my_app/doctype/task_tracker/task_tracker.json
Example JSON:
{
"doctype": "DocType",
"name": "Task Tracker",
"module": "Projects",
"custom": 0,
"is_submittable": 1,
"fields": [
{
"fieldname": "task_title",
"label": "Task Title",
"fieldtype": "Data",
"reqd": 1
},
{
"fieldname": "status",
"label": "Status",
"fieldtype": "Select",
"options": "Open\nIn Progress\nCompleted"
},
{
"fieldname": "due_date",
"label": "Due Date",
"fieldtype": "Date"
}
]
}
Step 3: Migrate Changes
Once saved, apply the schema to your database:
bench migrate
This creates the tabTask Tracker table in MariaDB with the specified fields.
DocType Database Structure in Frappe
When a DocType is created, Frappe automatically:
- Creates a MariaDB table prefixed with tab
- Maps each field to a column
- Adds system fields like:
- name (Primary Key)
- owner, creation, modified, docstatus, etc.
Example:
DESCRIBE `tabTask Tracker`;
Output:
| Field | Type | Null | Key | Default | Extra |
| name | varchar(140) | NO | PRI | NULL | |
| task_title | varchar(255) | YES | | NULL | |
| status | varchar(140) | YES | | NULL | |
| due_date | date | YES | | NULL | |
| owner | varchar(255) | YES | | NULL | |
Adding Logic to Your DocType
Server-Side Logic (Python)
In your controller file (task_tracker.py):
import frappe
from frappe.model.document import Document
class TaskTracker(Document):
def validate(self):
if self.status == "Completed" and not self.due_date:
frappe.throw("Please set a Due Date before marking as Completed")
Client-Side Logic (JavaScript)
In your client script (task_tracker.js):
frappe.ui.form.on("Task Tracker", {
refresh: function(frm) {
if (frm.doc.status === "Completed") {
frm.set_df_property("task_title", "read_only", 1);
}
}
});
Best Practices & Tips
- Use Singular names for DocTypes (e.g., “Invoice,” not “Invoices”).
- Keep fieldnames lowercase and snake_cased (customer_name, due_date).
- Avoid spaces in fieldname; Frappe uses these internally as database column names.
Enable Developer Mode during development to allow file-based JSON creation:
bench set-config developer_mode 1
bench restart
- Always run bench migrate after schema edits.
- Use Custom Fields instead of editing Core DocTypes for maintainability.
Troubleshooting Common Errors
Permission Error: Cannot create DocType
Enable developer mode:
bench set-config developer_mode 1
bench restart
Table already exists
You might have manually deleted JSON but not dropped the table.
Drop it manually via MariaDB:
DROP TABLE `tabTask Tracker`;
bench migrate
App Not Installed
Ensure your custom app is installed on the active site:
bench --site site-name.localhost install-app my_app
Cross-References and Related Guides
- How to Create a Site in Frappe Framework v15
- Understanding Frappe Apps and Modules
- Frappe Model Architecture (GitHub v15)
- ERPNext Developer Guide