Skip to main content

Database Migrations & Patches

As a Frappe application evolves, its database schema and stored data often need to change. Frappe provides a built-in migration system that synchronizes database structures, applies data patches, updates application components, and keeps existing sites compatible with the latest version of your app.

Overview

Whenever you modify DocTypes or introduce data-related changes, run a migration to update your site’s database safely. Frappe automatically applies schema updates, executes pending patches, and synchronizes various application components.

Running a Migration

To migrate an existing site to the latest version of your application, run:

bench --site [sitename] migrate

This command updates the site’s database schema, executes pending patches, rebuilds application resources, and synchronizes metadata.

Schema Changes

DocTypes define the structure of your application’s database tables. Whenever you add, remove, or modify fields in a DocType, Frappe updates the corresponding JSON definition stored inside your application’s source code.

Developer Mode must be enabled before making DocType schema changes.

During migration, Frappe compares each DocType’s JSON definition with the version already installed on the site. If changes are detected, the affected DocType is automatically reloaded and synchronized with the database.

Migration Workflow

When bench migrate is executed, Frappe performs the following operations in sequence:

  1. Runs the before_migrate hook to synchronize user permissions.
  2. Executes all pending patches.
  3. Synchronizes the database schema.
  4. Updates background jobs.
  5. Synchronizes fixtures.
  6. Updates dashboards, desktop icons, and web pages.
  7. Compiles and updates translations.
  8. Rebuilds the search index.
  9. Runs the after_migrate hook.

How Schema Changes Are Detected

Modern versions of Frappe compare the MD5 checksum of every DocType JSON file with the checksum stored in the database. If the hashes differ, that DocType is reloaded automatically. This checksum-based approach replaced timestamp comparisons beginning with Frappe v14, making migrations significantly more reliable.

Removing or Renaming Fields

When a field is removed or renamed, Frappe does not immediately delete the corresponding database column. The field disappears from the user interface, but the underlying database column remains available.

This behavior prevents accidental data loss and allows developers to write migration patches that transfer or transform existing data before obsolete columns are eventually removed.

Frappe does not support reverse schema migrations.

Data Migrations (Patches)

Sometimes updating the database structure isn’t enough. Existing records may also need to be modified to work correctly with new application logic. These one-time migration scripts are known as patches.

Writing a Patch

Create a Python file containing an execute() function and register it inside your application’s patches.txt file.

A common directory structure is shown below:

frappe
└── patches
    └── v12_0
        └── my_awesome_patch.py

The patch file should contain an execute() function:

def execute():
    # Write migration logic here
    pass

Then register the patch inside patches.txt:

frappe.patches.v12_0.my_awesome_patch

Working with Schema During a Patch

During patch execution, the DocType metadata still reflects the old schema. This allows migration scripts to safely access fields that existed before the upgrade.

If your patch requires the latest schema immediately, reload the DocType before executing the migration logic.

import frappe

def execute():
    frappe.reload_doc(module_name, "doctype", doctype_name)

    # your migration code

Post-Model Sync Patches

Beginning with Frappe v14, patches can be grouped into two execution stages inside patches.txt.

Section Purpose
[pre_model_sync] Runs before DocType schema synchronization. Suitable when patches depend on the old database structure.
[post_model_sync] Runs after all DocTypes have been synchronized. Suitable for patches that require the latest schema.

Example:

[pre_model_sync]
app.module.patch1
app.module.patch2

[post_model_sync]
app.module.patch3
app.module.patch4

One-Off Python Statements

Instead of creating a dedicated patch file, you can execute a single Python statement directly from patches.txt.

frappe.patches.v12_0.my_awesome_patch
execute:frappe.delete_doc('Page', 'applications', ignore_missing=True)

Patch Execution Order

Patches execute strictly in the order they appear inside patches.txt. Each entry is executed only once and is recorded after successful completion.

If you need to run an existing patch again, modify the line by adding a unique comment.

frappe.patches.v12_0.my_awesome_patch #2026-07-07

Best Practice

Keep schema changes and data migrations separate whenever possible. Use DocType modifications only for structural changes, and use patches for transforming existing data. Always test migrations on a staging environment before applying them to production sites.

Rating: 0 / 5 (0 votes)