Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/frappe/frappe/llms.txt

Use this file to discover all available pages before exploring further.

DocTypes are the foundation of Frappe’s metadata-driven architecture. A DocType defines the structure, behavior, and properties of a document type in your application.

What is a DocType?

A DocType is a metadata definition that describes:
  • Fields: The structure of data (field types, labels, options)
  • Permissions: Who can read, write, create, or delete documents
  • Behavior: Naming rules, validation logic, and workflow states
  • UI Configuration: Form layout, list views, and search fields
DocTypes are stored in the tabDocType table and are themselves documents that can be created and modified through Frappe’s interface.

Core DocType properties

Basic metadata

# Example: Getting DocType metadata
meta = frappe.get_meta('User')

print(meta.name)              # 'User'
print(meta.module)            # 'Core'
print(meta.is_submittable)    # False
print(meta.issingle)          # False (Single DocTypes have only one record)
print(meta.istable)           # False (Child tables)
print(meta.is_virtual)        # False (Virtual DocTypes don't have database tables)

Field definitions

DocTypes contain field definitions (DocFields) that specify the data structure:
# Get all fields
fields = meta.fields

# Get specific field
email_field = meta.get_field('email')
print(email_field.fieldtype)  # 'Data'
print(email_field.label)      # 'Email'
print(email_field.reqd)       # 1 (required)

# Get fields by type
link_fields = meta.get_link_fields()
table_fields = meta.get_table_fields()

Field types

Frappe supports numerous field types for different data needs:
  • Data: Short text (140 characters)
  • Text: Long text
  • Int: Integer numbers
  • Float: Decimal numbers
  • Currency: Monetary values
  • Date: Date values
  • Datetime: Date and time

Meta class API

The Meta class provides methods to inspect and work with DocType metadata:
from frappe.model.meta import get_meta

meta = get_meta('Sales Order')

# Check if field exists
if meta.has_field('customer'):
    print("Field exists")

# Get field label
label = meta.get_label('customer')  # "Customer"

# Get title field
title_field = meta.get_title_field()  # Field used as document title

# Get valid columns (database columns)
valid_columns = meta.get_valid_columns()

# Get search fields
search_fields = meta.get_search_fields()  # Fields used in search

Special DocType types

Single DocTypes

Single DocTypes have only one record (e.g., System Settings):
meta = frappe.get_meta('System Settings')
print(meta.issingle)  # True

# Single DocTypes use the name of the DocType as the document name
doc = frappe.get_doc('System Settings', 'System Settings')

Child DocTypes (Table fields)

Child DocTypes are used in table fields for one-to-many relationships:
meta = frappe.get_meta('Sales Order Item')
print(meta.istable)  # True

# Access child tables through parent
so = frappe.get_doc('Sales Order', 'SO-0001')
for item in so.items:  # 'items' is a Table field
    print(item.item_code, item.qty)

Virtual DocTypes

Virtual DocTypes don’t have physical database tables and manage their own data:
meta = frappe.get_meta('Virtual DocType')
print(meta.is_virtual)  # True

# Virtual DocTypes implement custom load_from_db() methods

Naming and AutoName

DocTypes define how documents are named:
meta = frappe.get_meta('Sales Order')

# AutoName options:
# - 'field:fieldname' - Use a field value as name
# - 'naming_series:' - Use a naming series (SO-.####)
# - 'Prompt' - User enters the name
# - 'autoname:EXPR' - Custom expression
# - '[field]' - Use specific field
print(meta.autoname)  # 'naming_series:'

# Get naming series options
series_options = meta.get_naming_series_options()
# Returns: ['SO-.YYYY.-', 'SO-.####.-']

Permissions

DocTypes define role-based permissions:
# Get permissions for a DocType
permissions = meta.get_permissions()

for perm in permissions:
    print(f"Role: {perm.role}")
    print(f"Read: {perm.read}")
    print(f"Write: {perm.write}")
    print(f"Create: {perm.create}")
    print(f"Delete: {perm.delete}")
    print(f"Submit: {perm.submit}")
    print(f"Cancel: {perm.cancel}")

Customization

DocTypes can be customized without modifying the original definition:
# Add custom fields via "Customize Form" or programmatically
custom_field = frappe.get_doc({
    'doctype': 'Custom Field',
    'dt': 'User',
    'fieldname': 'employee_id',
    'label': 'Employee ID',
    'fieldtype': 'Data',
    'insert_after': 'full_name'
})
custom_field.insert()

# Custom fields are automatically included in meta
meta = frappe.get_meta('User')
custom_fields = meta.get_custom_fields()

Working with DocTypes

Creating a new DocType programmatically

# Create a new DocType
doctype = frappe.get_doc({
    'doctype': 'DocType',
    'name': 'My Custom DocType',
    'module': 'Custom',
    'custom': 1,
    'fields': [
        {
            'fieldname': 'title',
            'label': 'Title',
            'fieldtype': 'Data',
            'reqd': 1
        },
        {
            'fieldname': 'description',
            'label': 'Description',
            'fieldtype': 'Text'
        }
    ],
    'permissions': [
        {
            'role': 'System Manager',
            'read': 1,
            'write': 1,
            'create': 1,
            'delete': 1
        }
    ]
})
doctype.insert()

Best practices

DocType metadata is automatically cached. Always use frappe.get_meta() instead of loading DocType documents directly:
# Good: Uses cache
meta = frappe.get_meta('User')

# Bad: Loads from database every time
meta = frappe.get_doc('DocType', 'User')
Use Meta methods to check fields instead of direct property access:
# Good
if meta.has_field('status'):
    status = doc.status

# Less safe
if 'status' in doc.__dict__:
    status = doc.status
Always check field properties before setting values:
field = meta.get_field('status')
if not field.get('read_only'):
    doc.status = 'Active'

Document class

Learn about Document instances and lifecycle

Forms

Understand form rendering and customization

Permissions

Deep dive into the permission system

Database layer

Explore database abstraction and queries