# Frappe Doctype Development

> Create and modify Frappe DocTypes including schema design, controllers, child tables, and customization. Use when building data models, adding fields, or implementing document lifecycle logic.

- **Type:** Skill
- **Install:** `agentstack add skill-lubusin-frappe-skills-frappe-doctype-development`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [lubusIN](https://agentstack.voostack.com/s/lubusin)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [lubusIN](https://github.com/lubusIN)
- **Source:** https://github.com/lubusIN/frappe-skills/tree/main/frappe-doctype-development

## Install

```sh
agentstack add skill-lubusin-frappe-skills-frappe-doctype-development
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Frappe DocType Development

Build and modify DocTypes—the core data model abstraction in Frappe Framework.

## When to use

- Creating new DocTypes (standard, single, child table, submittable, tree)
- Adding or modifying fields on existing DocTypes
- Implementing controller logic (validate, before_save, on_submit, etc.)
- Setting up naming series and auto-naming
- Configuring permissions and workflows
- Building child tables and parent-child relationships

## Inputs required

- Target app and module path
- DocType name and type (standard/single/child/submittable/tree)
- Field definitions (name, type, options)
- Permission requirements by role
- Whether workflow is needed

## Procedure

### 0) Verify environment

```bash
# Ensure developer mode is enabled
bench --site  console
>>> frappe.conf.developer_mode  # Must be True
```

### 1) Choose DocType type

| Type | Use Case | Key Setting |
|------|----------|-------------|
| Standard | Multiple records | Default |
| Single | Config/settings (one record) | `issingle: 1` |
| Child Table | Rows in parent table | `istable: 1` |
| Submittable | Draft→Submit→Cancel workflow | `is_submittable: 1` |
| Tree | Hierarchical data | `is_tree: 1` |
| Virtual | External data source | `is_virtual: 1` |

### 2) Create DocType

**Option A: Via UI (recommended for new DocTypes)**
1. Navigate to DocType List → New
2. Define fields, permissions, settings
3. Save (exports to app in developer mode)

**Option B: Via code**
```python
# Create DocType JSON in: 
# //doctype//.json
```

### 3) Define fields

Common field patterns:
```json
{
  "fieldname": "customer",
  "fieldtype": "Link",
  "label": "Customer",
  "options": "Customer",
  "reqd": 1
}
```

See [references/field-types.md](references/field-types.md) for all field types.

### 4) Implement controller

Create `.py` alongside the JSON:

```python
import frappe
from frappe.model.document import Document

class MyDocType(Document):
    def validate(self):
        # Lightweight validation
        if not self.customer:
            frappe.throw("Customer is required")
    
    def before_save(self):
        # Pre-save normalization
        self.full_name = f"{self.first_name} {self.last_name}"
    
    def after_insert(self):
        # Post-create side effects
        frappe.publish_realtime("new_doc", {"name": self.name})
```

### 5) Set up naming

```json
{
  "autoname": "naming_series:",
  "fields": [
    {
      "fieldname": "naming_series",
      "fieldtype": "Select",
      "options": "PRJ-.YYYY.-\nPRJ-.YYYY.-.###"
    }
  ]
}
```

Options: `field:fieldname`, `naming_series:`, `hash`, `format:PREFIX-{####}`

### 6) Configure permissions

Set in DocType → Permissions tab:
- Role + Read/Write/Create/Delete/Submit/Cancel
- User permissions for row-level filtering

### 7) Add workflow (if needed)

Create Workflow DocType linking to your DocType with states and transitions.

## Verification

- [ ] DocType appears in list and can create new records
- [ ] All fields save correctly
- [ ] Controller hooks fire (check logs)
- [ ] Permissions enforced for each role
- [ ] Naming series generates correctly
- [ ] Run: `bench --site  migrate` succeeds

## Failure modes / debugging

- **DocType not found**: Check module path and app installation
- **Controller not loading**: Verify class name matches DocType name (PascalCase)
- **Fields not saving**: Check fieldtype and options compatibility
- **Permission denied**: Verify role permissions and User Permissions

## Escalation

- For complex permission logic, see [references/permissions.md](references/permissions.md)
- For child table patterns, see [references/child-tables.md](references/child-tables.md)
- For Virtual DocTypes, see [references/virtual-doctypes.md](references/virtual-doctypes.md)

## References

- [references/field-types.md](references/field-types.md) - All field types and options
- [references/controllers.md](references/controllers.md) - Controller lifecycle hooks
- [references/child-tables.md](references/child-tables.md) - Parent-child patterns
- [references/naming.md](references/naming.md) - Naming patterns

## Guardrails

- **Check developer_mode before schema changes**: DocType modifications only export to files when `developer_mode = 1` in site config
- **Verify naming series uniqueness**: Ensure naming series prefixes don't conflict with existing DocTypes
- **Test child tables separately**: Child tables have their own lifecycle; test them in isolation before parent integration
- **Always run migrate after changes**: Schema changes require `bench --site  migrate` to apply
- **Validate fieldname conventions**: Use snake_case, max 140 chars, no reserved SQL keywords

## Common Mistakes

| Mistake | Why It Fails | Fix |
|---------|--------------|-----|
| Missing `reqd` on mandatory fields | Users can save incomplete data | Set `reqd: 1` on fields that must have values |
| Wrong fieldtype for data | Data truncation or validation errors | Match fieldtype to data (e.g., `Currency` for money, not `Float`) |
| Not running `bench migrate` | Schema changes not applied to database | Always run `bench --site  migrate` after DocType changes |
| Circular Link dependencies | DocType creation fails | Use Dynamic Link or restructure relationships |
| Controller class name mismatch | Controller methods not called | Class name must be PascalCase of DocType name (e.g., `SalesOrder` for "Sales Order") |
| Missing `in_list_view` on key fields | Fields not visible in list | Set `in_list_view: 1` on important fields |

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [lubusIN](https://github.com/lubusIN)
- **Source:** [lubusIN/frappe-skills](https://github.com/lubusIN/frappe-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-lubusin-frappe-skills-frappe-doctype-development
- Seller: https://agentstack.voostack.com/s/lubusin
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
