Monkey Patching in Frappe: Override Core Logic the Clean Way

Learn how to safely override core functionality in Frappe and ERPNext using monkey patching

 · 3 min read

🔍 What is Monkey Patching?

Monkey patching means replacing an existing function or method with your version while the app is running.

In Python (which Frappe is built on), this is easy because everything is an object. That means we can load a function from the system and then swap it with our version.

With this, you can:

  1. Replace a function in Frappe or ERPNext without touching the original files
  2. Add your business logic
  3. Make system-wide changes without breaking future updates

Why Should You Use Monkey Patching?

Monkey patching isn’t always the first option, but it’s super helpful when:

🔁 You want custom logic

Maybe you want to change how a Sales Invoice is validated or add a message before it submits.

You want to keep your changes safe

If you edit core files directly, those changes will disappear when you update. Monkey patching keeps your custom logic in your own app — so updates won't break your system.

There's no hook or event

Frappe gives us a lot of ways to customize (like doc_events), but sometimes there’s no official way to override a method. Monkey patching solves that.

🧠 How Does Monkey Patching Work in Frappe?

There are just a few simple steps:

✅ Step 1: Create your custom logic

You write your own version of the method you want to change.

✅ Step 2: Replace the original method with your version

You tell Frappe, “Hey, use my function instead of the built-in one.”

✅ Step 3: Make sure this replacement happens when the app starts

You do this by linking your patch file in your app’s hooks.py, so it loads automatically.

Keep It Clean: Use One File for All Patches

Here’s a best practice: keep all your monkey patches in one place.

Create a folder like this in your custom app:

kotlin
CopyEdit
custom_app/
├── monkey_patches/
│   └── __init__.py   ← this is where all your patch code goes
├── hooks.py

Why use one file?

  1. ✅ Everything is easy to find
  2. ✅ No confusion about where patches are
  3. ✅ It’s easier to debug and update later

When Not to Use Monkey Patching

Monkey patching is powerful — but it’s not always the best choice.

Don’t use monkey patching if:

  1. There's already a built-in hook (doc_events, override_whitelisted_methods, etc).
  2. You can subclass a controller or use a custom Doctype instead
  3. You want to avoid future maintenance headaches
  4. You’re not sure if a method will change often in future updates

Always check if there's a cleaner way before monkey patching.

Summary

Monkey patching is a great tool when:

  1. You want to customize Frappe or ERPNext behavior
  2. You can’t use standard hooks
  3. You want your changes to survive updates

But — keep it clean:

  1. Put all patches in one file (monkey_patches/__init__.py)
  2. Link that file in hooks.py so it loads when the app starts

With this setup, you can safely customize your system without ever touching core files.



Example: Monkey Patching ERPNext Tax Functions (No Extra Files)

In this example, we wanted to customize how ERPNext handles tax breakup display (both HTML and data), without modifying any core files.

✅ Patch Directly from hooks.py

Instead of keeping monkey patch logic in a separate patch file, we wrote it directly in hooks.py:


import erpnext.controllers.taxes_and_totals
import india_compliance.gst_india.overrides.transaction
import your_custom_app.overrides.custom_taxes as custom_taxes


# Apply monkey patches
erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_html = custom_taxes.custom_get_itemised_tax_breakup_html
erpnext.controllers.taxes_and_totals.get_itemised_tax_breakup_data = custom_taxes.custom_get_itemised_tax_breakup_data
india_compliance.gst_india.overrides.transaction.get_itemised_tax_breakup_data = custom_taxes.custom_get_itemised_tax_breakup_data

This makes the patch apply automatically when the app is installed or the server restarts — no need to touch doc_events or add a custom __init__.py.

✅ Write Your Custom Functions

Then, in your app's code (e.g. custom_app/overrides/custom_taxes.py), define the new behavior for tax functions. These will now override ERPNext’s default logic.

Why This Works

  1. Hook files run early during boot, so the patch is guaranteed to be in place before any document or request needs the function.
  2. It keeps the patch logic visible and central — easy to track.
  3. No core changes, no app conflicts, and upgrade-safe.

So, in summary:

  1. Monkey patch logic = in hooks.py
  2. Custom function = in your own app's Python file
  3. No extra hooks or doc_events needed

Add a comment
Ctrl+Enter to add comment

T
MahaRaja 3 days ago

can You Help Me To Fix it

T
MahaRaja 3 days ago

I have Tried This it is Working In Local / server but Failed In Frappe Cloud some times it is working Some times not working