Skip to main content

Chapter 1 of 7 · The model

What a DocType is

One definition that becomes a table, a form, an API and a permission set.

Reviewed 14 Oct 20263 min readFrappe v16.52.0

A DocType is one record definition. You write it once, as a JSON file in an app or as a Custom DocType in the Desk, and Frappe builds four things from it: a database table, a form and list view, a REST endpoint, and a place to hang permissions. The rest of this book is about what Frappe does with that definition.

The module below shows the first three for any field type. Pick one, and switch the database.

Try it

Field type → what Frappe builds

Pick a field type and a database. MariaDB is Frappe's default.

Group

Field type

Database

Database column
decimal(21,9)
Form control
ControlCurrency
What the API sends
number, for example 1250.5

Width and precision are configurable; the default is 21,9.

Sample values are illustrative. Frappe v16.52.0; Check differs on v15.123.0.

What does one field become?

The field type decides everything. Frappe keeps a map from field type to column type, and names the form control after the type. A Currency field is a decimal(21,9) column on MariaDB, a ControlCurrency in the form, and a number in the API. A Check is tinyint(4) on v16 and int(1) on v15, a tick box in the form, and 0 or 1 in the API. A Link is a varchar(140) that holds the other document's name, and the API returns that name, not the document. A Date is a date column that the API sends as a string such as 2026-04-01.

Text types hold more or less. Data, Select, Link and Phone are varchar(140) by default. Small Text and Text are text. Long Text, Code and the editors are longtext. Set a length on a Data field and the column follows, never below 64. A Link to a DocType that is named by UUID becomes a uuid column. PostgreSQL has its own map, which the module shows.

Which fields have no column?

Layout fields: Section Break, Column Break, Tab Break, HTML, Button and Image. A Table field has no column either. Its rows belong to another DocType, the child table, which has its own table with parent, parentfield and parenttype columns, and the API nests those rows under the field's name. A Password value goes to a separate __Auth table, and the field itself holds asterisks.

What does every table have?

Every table also gets name, creation, modified, modified_by, owner, docstatus and idx. The table is named tab plus the DocType's name, so Sales Invoice is tabSales Invoice. A Single DocType, used for settings, has no table of its own: its values are rows in tabSingles.

How does it reach the API?

GET /api/resource/Sales Invoice/SINV-00001 returns the document inside a data key, with its child rows nested. POST runs insert() and PUT runs save(), so an API write goes through the same lifecycle as a click in the Desk (chapter 2). A read also checks read permission and removes the fields the user may not read (chapter 4).

Where does the definition live?

For a standard DocType it is a JSON file in the app, under <app>/<module>/doctype/<name>/<name>.json. bench migrate reads it and brings the table in line. You can create a standard DocType only in developer mode. On a live site you create a Custom DocType, which has no Python class of its own, so its logic comes from a Server Script or a doc_events hook (chapter 3). Changes to someone else's DocType are not edits to its file. They are rows layered on top (chapter 7).

Where this comes from

Read at Frappe v16.52.0 and ERPNext v16.50.0. “(v15)” marks Frappe v15.123.0 and “(ERPNext v15)” marks ERPNext v15.122.0. Each link opens that file at that tag, on that line.

Official page: Understanding DocTypes, read 14 October 2026. Platform view: what Frappe gives a business, and what still gets built.

Your next step

See it live

Run a sprint

Finish a task in this week's sprint, log the hour it took, and see the sprint's burndown, all on ERPNext's own records.

You end with hours booked on a task · 2 screens · about 3 min

No sign-up, no card, no account.

Next step · Architecture guide

Now see how we build a Frappe app

A separate app in your own Git, so upgrades keep working.