to select ↑↓ to navigate
Frappe Framework

Frappe Framework

Open in ChatGPT
Ask ChatGPT about this page
Open in Claude
Ask Claude about this page

Document Lifecycle

Document Lifecycle

Every Frappe document goes through a defined lifecycle. Hooks fire at each stage — apps can validate, react, or veto.

Stages

Stage When Common use
before_insert Just before first save (record doesn't exist yet) Compute defaults from context
after_insert After first save Create related records
validate Before every save (insert OR update) Business rule checks
before_save Before every save Final adjustments
on_update After every save Sync to external systems
before_submit Before submit Final checks before locking
on_submit After submit Create GL Entries, trigger workflow
before_cancel Before cancel Verify cancellation allowed
on_cancel After cancel Reverse GL Entries
on_trash Before delete Cleanup

Submittable documents

Documents like Sales Invoice, Stock Entry, Journal Entry are submittable:

docstatus Meaning Editable?
0 Draft Yes
1 Submitted (finalized; ledger entries created) No — Cancel + Amend
2 Cancelled (reversed) No

You don't delete submitted documents — you Cancel and (optionally) Amend.

Hook resolution

For each lifecycle stage, Frappe runs:

  1. The DocType's controller method (e.g., before_save(self))
  2. App doc_events hooks (in install order)

Multiple apps can hook the same event. Errors from any hook abort the save — partial state never persists.

Idempotency

Don't assume hooks fire only once per "user action". A retry, a queued job, or a script can trigger the same event multiple times. Design hooks to be idempotent — re-running them shouldn't double-charge or double-create.

Last updated 3 days ago
Was this helpful?
Thanks!