erpnext-syntax-customapp

ERPNext Custom App Syntax Skill

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "erpnext-syntax-customapp" with this command: npx skills add openaec-foundation/erpnext_anthropic_claude_development_skill_package/openaec-foundation-erpnext-anthropic-claude-development-skill-package-erpnext-syntax-customapp

ERPNext Custom App Syntax Skill

Complete syntax for building Frappe custom apps in v14/v15, including build configuration, module organization, patches and fixtures.

When to Use This Skill

USE this skill when you:

  • Create a new Frappe/ERPNext custom app

  • Configure pyproject.toml or setup.py

  • Organize modules within an app

  • Write database migration patches

  • Configure fixtures for data export/import

  • Manage app dependencies

DO NOT USE for:

  • DocType controllers (use erpnext-syntax-controllers)

  • Client Scripts (use erpnext-syntax-clientscripts)

  • Server Scripts (use erpnext-syntax-serverscripts)

  • Hooks configuration (use erpnext-syntax-hooks)

App Structure Overview

v15 (pyproject.toml - Primary)

apps/my_custom_app/ ├── pyproject.toml # Build configuration ├── README.md ├── my_custom_app/ # Main package │ ├── init.py # MUST contain version! │ ├── hooks.py # Frappe integration │ ├── modules.txt # Module registration │ ├── patches.txt # Migration scripts │ ├── patches/ # Patch files │ ├── my_custom_app/ # Default module │ │ └── doctype/ │ ├── public/ # Client assets │ └── templates/ # Jinja templates └── .git/

See: references/structure.md for complete directory structure.

Critical Files

init.py (REQUIRED)

my_custom_app/init.py

version = "0.0.1"

CRITICAL: Without version the flit build fails!

pyproject.toml (v15)

[build-system] requires = ["flit_core >=3.4,<4"] build-backend = "flit_core.buildapi"

[project] name = "my_custom_app" authors = [ { name = "Your Company", email = "dev@example.com" } ] description = "Description of your app" requires-python = ">=3.10" readme = "README.md" dynamic = ["version"] dependencies = []

[tool.bench.frappe-dependencies] frappe = ">=15.0.0,<16.0.0" erpnext = ">=15.0.0,<16.0.0"

See: references/pyproject-toml.md for all configuration options.

Modules

modules.txt

My Custom App Integrations Settings Reports

Rules:

  • One module per line

  • Spaces in name → underscores in directory

  • Every DocType MUST belong to a module

Module Directory

my_custom_app/ ├── my_custom_app/ # "My Custom App" module │ ├── init.py # REQUIRED │ └── doctype/ ├── integrations/ # "Integrations" module │ ├── init.py # REQUIRED │ └── doctype/ └── settings/ # "Settings" module ├── init.py # REQUIRED └── doctype/

See: references/modules.md for module organization.

Patches (Migration Scripts)

patches.txt with INI Sections

[pre_model_sync]

Before schema sync - old fields still available

myapp.patches.v1_0.backup_old_data

[post_model_sync]

After schema sync - new fields available

myapp.patches.v1_0.populate_new_fields myapp.patches.v1_0.cleanup_data

Patch Implementation

myapp/patches/v1_0/populate_new_fields.py

import frappe

def execute(): """Populate new fields with default values."""

batch_size = 1000
offset = 0

while True:
    records = frappe.get_all(
        "MyDocType",
        filters={"new_field": ["is", "not set"]},
        fields=["name"],
        limit_page_length=batch_size,
        limit_start=offset
    )
    
    if not records:
        break
    
    for record in records:
        frappe.db.set_value(
            "MyDocType",
            record.name,
            "new_field",
            "default_value",
            update_modified=False
        )
    
    frappe.db.commit()
    offset += batch_size

When Pre vs Post Model Sync?

Situation Section

Migrate data from old field [pre_model_sync]

Populate new fields [post_model_sync]

Data cleanup [post_model_sync]

See: references/patches.md for complete patch documentation.

Fixtures

hooks.py Configuration

fixtures = [ # All records "Category",

# With filter
{
    "dt": "Custom Field",
    "filters": [["module", "=", "My Custom App"]]
},

# Multiple filters
{
    "dt": "Property Setter",
    "filters": [
        ["module", "=", "My Custom App"],
        ["doc_type", "in", ["Sales Invoice", "Sales Order"]]
    ]
}

]

Exporting

bench --site mysite export-fixtures --app my_custom_app

Common Fixture DocTypes

DocType Usage

Custom Field

Custom fields on existing DocTypes

Property Setter

Modify field properties

Role

Custom roles

Workflow

Workflow definitions

See: references/fixtures.md for fixture configuration.

Minimal hooks.py

app_name = "my_custom_app" app_title = "My Custom App" app_publisher = "Your Company" app_description = "Description" app_email = "dev@example.com" app_license = "MIT"

required_apps = ["frappe"] # Or ["frappe", "erpnext"]

fixtures = [ {"dt": "Custom Field", "filters": [["module", "=", "My Custom App"]]} ]

Creating and Installing App

Create new app

bench new-app my_custom_app

Install on site

bench --site mysite install-app my_custom_app

Migrate (patches + fixtures)

bench --site mysite migrate

Build assets

bench build --app my_custom_app

Version Differences

Aspect v14 v15

Build config setup.py pyproject.toml

Dependencies requirements.txt In pyproject.toml

Build backend setuptools flit_core

Python minimum

=3.10 =3.10

INI patches ✅ ✅

Critical Rules

✅ ALWAYS

  • Define version in init.py

  • Add dynamic = ["version"] in pyproject.toml

  • Register modules in modules.txt

  • Include init.py in EVERY directory

  • Put Frappe dependencies in [tool.bench.frappe-dependencies]

  • Add error handling in patches

  • Use batch processing for large datasets

❌ NEVER

  • Put Frappe/ERPNext in project dependencies (not on PyPI)

  • Create patches without error handling

  • Include user/transactional data in fixtures

  • Hardcode site-specific values

  • Process large datasets without batching

Fixtures vs Patches

What Fixtures Patches

Custom Fields ✅ ❌

Property Setters ✅ ❌

Roles/Workflows ✅ ❌

Data transformation ❌ ✅

Data cleanup ❌ ✅

One-time migration ❌ ✅

Reference Files

File Contents

references/structure.md

Complete directory structure

references/pyproject-toml.md

Build configuration options

references/modules.md

Module organization

references/patches.md

Migration scripts

references/fixtures.md

Data export/import

references/examples.md

Complete app examples

references/anti-patterns.md

Mistakes to avoid

See Also

  • erpnext-syntax-hooks

  • For hooks.py configuration

  • erpnext-syntax-controllers

  • For DocType controllers

  • erpnext-impl-customapp

  • For implementation patterns

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

erpnext-code-interpreter

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-syntax-jinja

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-impl-controllers

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

erpnext-database

No summary provided by upstream source.

Repository SourceNeeds Review