# Fixtures (ERPNext glossary)

Canonical: https://erpfly.com/glossary/fixtures/
Last updated: September 14, 2026

**Definition:** Fixtures are database records, such as Custom Fields, Property Setters, Roles or Workflows, that a Frappe app exports to JSON files in its fixtures folder. Frappe imports those files whenever the app is installed and on every bench migrate, so each site running the app ends up with the same records.

Also called: Frappe fixtures, export-fixtures, ERPNext fixtures

Most ERPNext configuration lives in the database, not in code. A field someone added through Customize Form, a new role, a workflow for purchase approvals: all of them are rows, and rows don't travel with `git pull`. Fixtures are how a Frappe app takes those rows along.

### How records get in and out

You list the DocTypes you want in the `fixtures` variable of your app's hooks.py. An entry can be a plain DocType name, which exports every record of that type, or a dict with `dt` plus `filters` or `or_filters` to narrow it down.

Running `bench export-fixtures` reads that list and writes one JSON file per entry into `<app>/fixtures/`, named after the DocType (`custom_field.json`, `property_setter.json` and so on). System fields like `owner`, `creation` and `modified_by` are left out, so the files diff reasonably well in a pull request.

Going the other way, `bench migrate` and app installation both import every JSON file in that folder. The import is forced. It doesn't compare timestamps, so whatever is in the file replaces what's in the database.

### A filtered fixtures list

```python
# acme_custom/hooks.py
fixtures = [
    {"dt": "Custom Field", "filters": [["module", "=", "Acme Custom"]]},
    {"dt": "Property Setter", "filters": [["module", "=", "Acme Custom"]]},
    {"dt": "Role", "filters": [["name", "in", ["Credit Controller"]]]},
]
```

```bash
bench --site erp.example.com export-fixtures --app acme_custom
```

Filtering on `module` only works if you set the Module on each Custom Field and Property Setter when you create it. That habit is most of the discipline fixtures need. It's also how erpfly packages customizations: every record it creates carries the app's module, so the export picks up those records and nothing that belongs to another app.

### Where teams get burned

**No filter.** `fixtures = ["Custom Field"]` exports every custom field on the site, including ones created by other installed apps. Install your app somewhere else and it starts overwriting fields it doesn't own.

**Editing on production afterwards.** Because the import is forced, a label changed in the browser on production reverts on the next migrate. Change the record on a development site, export again, commit.

**Expecting deletes to sync.** Removing a record from the JSON doesn't remove it from sites that already have it. Fixture sync only inserts and updates. Delete it with a patch if it really has to go.

**Forgetting dependencies.** A Workflow refers to Workflow State and Role records. Export those alongside it so a fresh site has everything the workflow points at.

On v16, `export-fixtures` refuses DocType and Page as fixture entries. New DocTypes belong in the app's module folder, created in developer mode.

### Fixtures or Export Customizations

Customize Form has an Export Customizations button, available in developer mode. It writes the Custom Fields and Property Setters for one DocType (and its child tables) to `<module>/custom/<doctype>.json`, and they're applied on migrate if you tick "sync on migrate". That's fine for a single form. Fixtures cover any DocType and a whole app's worth of records from one list, which is why we prefer them. Our guide to [keeping customizations through an ERPNext upgrade](https://erpfly.com/blog/erpnext-upgrade-keep-customizations/) shows where fixtures fit in a staging routine, and the [ERPNext customization](https://erpfly.com/erpnext-customization/) page covers the rest of the packaging.

See also: https://erpfly.com/glossary/hooks-py/, https://erpfly.com/glossary/custom-field/, https://erpfly.com/glossary/frappe-app/, https://erpfly.com/glossary/bench/

### Sources

- [Hooks: Fixtures, Frappe Framework documentation](https://docs.frappe.io/framework/user/en/python-api/hooks)
- [frappe/utils/fixtures.py (version-15), frappe/frappe on GitHub](https://github.com/frappe/frappe/blob/version-15/frappe/utils/fixtures.py)
- [frappe/modules/utils.py, export_customizations (version-15), frappe/frappe on GitHub](https://github.com/frappe/frappe/blob/version-15/frappe/modules/utils.py)