Hooks in Frappe Framework v15
What are Hooks in Frappe?
Hooks are a declarative configuration mechanism in hooks.py that allow developers to extend, override, or inject functionality into Frappe and ERPNext without editing the core code. Hooks enable custom applications to connect logic to framework events such as DocType events, scheduled tasks, API endpoints, UI assets, and more.
In Frappe v15, hooks are the primary mechanism for integration, used to implement business logic, add custom controllers, and register services inside a modular app.
How do Hooks work in Frappe?
Frappe loads hooks.py from every installed app at startup.
During runtime, when Frappe reaches a hook point (e.g., document event, scheduler time, page load), it resolves registered methods and executes them.
Hook entries follow this structure:
# content example (simplified)
doc_events = {
"Sales Invoice": {
"validate": "my_app.api.validate_invoice"
}
}
Here, when Sales Invoice.validate event triggers, Frappe will call the method defined in the hook.
Why use Hooks instead of modifying core?
Hooks enable:
- Zero core modification (upgrade-safe)
- Clean modular architecture
- Event-driven custom logic
- Central configuration of integrations
- Ability to override framework behavior
- Ability to register routes and scheduler jobs
Hooks are the preferred customization method in production systems.
Structure of hooks.py in Frappe Apps
Every app created using:
bench new-app my_app
contains a default hooks.py file at:
my_app/my_app/hooks.py
This file defines all configuration entries used to integrate that app into the Frappe environment.
Core Hook Categories in Frappe v15
There are multiple hook types grouped by functionality.
Below are the standard classes of hooks.
1. DocType Event Hooks
What are DocType Hooks?
DocType Hooks allow you to register functions that are triggered during the lifecycle of a document, including:
- validate
- before_save
- on_update
- on_submit
- on_cancel
- on_trash
Use this to implement business logic:
doc_events = {
"Purchase Order": {
"validate": "my_app.api.validate_po"
}
}
2. Scheduled (Cron-like) Hooks
Hooks allow you to register background jobs that run on time intervals.
scheduler_events = {
"daily": [
"my_app.tasks.cleanup_old_logs"
],
"hourly": [
"my_app.tasks.pull_data"
],
}
Supported intervals include:
- all
- daily
- hourly
- weekly
- monthly
- cron (custom)
This enables automated workflows like reconciliation, cleanup jobs, and integrations.
3. Website & Web Page Hooks
Hooks allow registering pages and web forms without modifying core routing.
website_route_rules = [
{"from_route": "/shop", "to_route": "Shop Home"}
]
You can also define website assets in hooks for CSS/JS bundling.
4. REST API Whitelisting Hooks
To expose Python functions as HTTP APIs:
override_whitelisted_methods = {
"frappe.desk.doctype.event.event.get_events": "my_app.api.get_custom_events"
}
Or whitelist your own method:
api_methods = [
"my_app.api.get_data"
]
When whitelisted, methods can be called via:
/api/method/my_app.api.get_data
5. Override Core Logic
You can override framework classes or controller logic, allowing deep customization.
override_doctype_class = {
"Item": "my_app.overrides.CustomItem"
}
This approach lets you customize ERPNext DocType behavior at class level.
6. Fixtures & Custom Fields Injection
Hooks can define exportable fixtures such as:
- Custom Fields
- Property Setters
- Print Formats
fixtures = [
"Custom Field",
"Property Setter"
]
This allows migration of UI settings from development to production.
7. Asset Bundling Hooks
To include JS/CSS into Desk:
app_include_js = "/assets/my_app/js/custom.js"
app_include_css = "/assets/my_app/css/style.css"
Useful for UI customization.
8. Document Creation Hooks
You can define default values or field transformations using hooks.
before_install = "my_app.install.before_install"
after_install = "my_app.install.after_install"
How to Implement Hooks (Step-by-Step)
Step 1: Create a Frappe App
bench new-app my_app
bench install-app my_app
Step 2: Open hooks.py
cd apps/my_app/my_app
nano hooks.py
Step 3: Add Hook Configuration
Example: DocType validate event
doc_events = {
"Sales Order": {
"validate": "my_app.api.validate_so"
}
}
Step 4: Create the Python Function
# my_app/api.py
import frappe
def validate_so(doc, method):
# business logic here
if not doc.items:
frappe.throw("Items required")
Step 5: Reload and Test
bench restart
bench --site site1.local execute my_app.api.validate_so
Best Practices for Hooks in Frappe v15
1. Use fully qualified import paths
Always use full paths: “my_app.api.validate_so”.
2. Avoid heavy logic inside Document events
Offload heavy tasks to background jobs when possible.
3. Keep hooks.py clean
Organize logic in files, not inside the hook definition.
4. Use Scheduler for integrations
Instead of calling APIs on every save, use cron hooks.
5. Avoid overriding core when possible
Use events instead of override class unless necessary.
6. Test hooks under load
Especially scheduled jobs.
7. Always log exceptions
Use frappe.log_error() inside hooks for traceability.
Troubleshooting Common Hook Issues
Hooks not triggering?
- Ensure the app is installed on the site.
- Use bench restart after changes.
- Confirm spelling of DocType.
Review error logs using:
bench --site site1.local logs
Scheduler not running?
- Ensure Redis Queue is running.
Enable scheduler:
bench enable-scheduler
API override not applying?
- Verify the correct dotted path.
- Confirm the original API is safe to override.
Recommended Use Cases
Hooks are ideal when:
- You need to insert business rules into DocType lifecycle
- You want to schedule background integrations
- You want to expose custom APIs
- You are building module extensions for ERPNext
- You want to auto-create data or enrich fields
- You want to override print formats
- You want system-wide UI customization
Industry Relevance & Why It Matters
Companies implementing ERPNext often need:
- Validation rules (e.g., stock check)
- Auto-create transactions (e.g., delivery on submit)
- Payment gateway integration
- 3rd-party API sync (CRM, HRIS, POS)
- Automated reports
- Extended accounting logic
Hooks allow all of this without touching ERPNext core, supporting upgrade safety and modular deployments.
Target Audience
- ERPNext implementation teams
- Frappe backend developers
- Integration engineers
- System architects
- Consultants designing custom workflows
Technical Prerequisites
- Familiarity with Python
- Frappe app development basics
- Understanding of DocType lifecycle
- Ability to run commands via Bench
Cross-References
To fully understand Hooks, explore these related concept guides:
- Frappe Routing API
- Background Jobs API
- Frappe Response API
- Server Scripts vs Hooks
- Scheduler Events
- Document Lifecycle Events