Back to the blog Business Applications

Custom Fields Are Not Just a Feature: How to Evaluate Data-Model Flexibility in a Self-Hosted Business Application

Custom fields can either make a business application fit your process or create inconsistent, inaccessible, and difficult-to-migrate data. Use this evidence-based framework to test the underlying data model before committing operational records.

Operations team mapping entities, relationships and governed custom fields in a self-hosted business application

Custom fields are a data-governance decision, not a checkbox

A product page saying “custom fields supported” answers very little. A field might be an unrestricted text box, a controlled list of permitted values, a link to another record, or a repeatable table of related records. Those choices determine whether people can enter consistent data, whether the application can enforce business rules, and whether the information remains useful in reports, exports, and integrations.

Treat the evaluation as a question of data-model fit: can the application represent the entities, relationships, and rules your operation actually uses? A quick configuration demo is not sufficient evidence. You need to see how the same custom information behaves when records are created, edited, finalized, searched, exported, imported, and accessed by users with different permissions.

This is especially important for a self-hosted application. Hosting gives you control over where the workload runs, but it does not decide which fields should exist, who may access them, how a retired value is interpreted, or whether an integration depends on a field definition. Those are governance decisions your organization must make.

  • Do not score “custom fields: yes/no.” Score the complete lifecycle of a representative field.
  • Separate user-interface convenience from enforced data rules and access control.
  • Ask for evidence in a test environment using your own realistic records, not only vendor examples.
Custom fields are a data-governance decision, not a checkbox

Start with a small, real record model

Before opening a trial instance, write down one small but consequential workflow. A service-delivery record, customer account, purchase request, or project change request is usually a better starting point than an abstract list of desired fields. Include information that is shared across the record, information that belongs to another entity, and information that repeats.

For each item, decide what it means structurally. A free-text note is appropriate when variation is expected and no reliable grouping is required. A controlled value is more appropriate for a business status, category, or reason that must be consistently filtered and reported. A relationship is appropriate when the value is really another maintained entity, such as a customer, supplier, or owner. Repeating related items should be modeled as repeated rows where the application supports that pattern, rather than packed into a comma-separated text field.

Frappe’s documentation illustrates these distinctions: Data is generic text; Select uses values specified in its options; Link connects to another master; and Table represents a child-table relationship. Its Child DocType documentation also describes child records as attached to a parent, retaining parent and row-sequence information. The precise names differ across products, but the evaluation question is universal: does the available structure match the meaning of your information? See Frappe’s Field Types documentation (https://docs.frappe.io/framework/user/en/basics/doctypes/fieldtypes) and Child / Table DocType documentation (https://docs.frappe.io/framework/user/en/basics/doctypes/child-doctype).

  • List the primary entities: for example, customer, project, request, and person.
  • Identify one-to-one, one-to-many, and many-to-one relationships.
  • Mark every value that must be controlled rather than freely typed.
  • Identify repeating data, such as multiple contacts, milestones, items, or approvals.
  • Write the business rules that make a record complete or valid.
Start with a small, real record model

Verify field types and rules in official documentation

Read the application’s official documentation for field types and rule configuration, then verify those capabilities in the version you plan to use. Look beyond whether a field can be added. Establish whether it can be required, supplied with a default, validated, limited to controlled values, and made conditionally required or read-only.

For example, Frappe documents independent settings for default values, mandatory_depends_on, and read_only_depends_on. That makes it possible, in principle, to test rules such as requiring a reason when a record reaches a particular state, or preventing further edits when a condition is met. Do not infer that another application has identical behavior simply because both offer custom fields. See the Frappe DocField documentation: https://docs.frappe.io/framework/user/en/basics/doctypes/docfield.

Test invalid inputs deliberately. Can a user leave a required value blank? Can they choose an invalid category? Is a default visible and understandable? Does the application enforce the rule at save time, import time, and API time where those routes are relevant? A rule that works only on one form can still leave inconsistent records elsewhere.

  • Create a required field and attempt to save without it.
  • Add a default and verify when it is applied.
  • Use a controlled-value field for a reporting category; try to enter an unapproved value.
  • Test a condition that makes a field required or read-only.
  • Record whether each rule is enforced in the interface, imports, and supported APIs.

Test consistency across records, teams, and workflows

A usable configuration must apply consistently at the scale of your operation. Create several records through the normal workflow, using different users or roles if possible. Confirm that each team sees the same intended field definitions, defaults, and controlled values where policy requires consistency.

Pay particular attention to workflow boundaries. A field that can be edited after a document is finalized may change its meaning, status, value, or downstream effects. Frappe’s Allow on Submit guidance explicitly cautions that editable post-submission fields should be safe to change and calls out dependencies in reports, workflows, integrations, permissions, and server-side logic. Use that principle even if you are evaluating another platform. See Frappe’s Allow on Submit documentation: https://docs.frappe.io/framework/doctypes/allow-on-submit.

Where a process needs historical truth, decide which values must remain fixed after approval or finalization and which are operationally safe to amend. Record the result as a rule, not an informal expectation.

  • Create equivalent records in more than one team context.
  • Compare field availability, values, and defaults.
  • Move a record through its meaningful status or approval stages.
  • Attempt permitted and prohibited edits after finalization.
  • Identify reports, integrations, and permissions affected by each editable field.

Assess permissions separately for records, fields, reports, exports, and imports

Permission testing should not stop at “can this user open the record?” Determine who can view, create, edit, and delete records; who can see or edit sensitive fields; and who can change the field definition itself. Also test reporting, exports, and imports independently. A person who cannot change a record may still be able to export information if that capability is granted separately.

Frappe documents distinct permissions for reading, writing, creating, deleting, viewing reports, CSV/Excel export, and use of its Data Import Tool. It also documents permission levels that can group fields and apply different roles to each level. These examples show why a single broad permissions check is inadequate. See Frappe’s Users and Permissions documentation: https://docs.frappe.io/framework/user/en/basics/users-and-permissions.

Do not treat hidden fields as secure by default. Establish, through official product documentation and a restricted-account test, whether sensitive fields are omitted from forms, reports, exports, and supported remote-access methods—and whether direct attempts to read or write them are denied. Test the behavior of the specific product and version you are considering rather than assuming that a visibility setting is an access control.

  • Test a standard user, a manager, a reporting user, and an administrator.
  • Attempt to view, edit, and create sensitive field values with each role.
  • Test report access and data export as separate actions.
  • Test whether an import user can populate restricted fields.
  • Use a restricted account to attempt supported API reads and writes of sensitive data.
  • Document who can alter field definitions and controlled-value lists.

Check whether custom data works where decisions are made

A custom field is operationally valuable only if people can use it beyond the record form. Test it in list views, filters, sorting, saved views, dashboards, reports, and exports. Verify that the results are understandable when a field is empty, when values change over time, and when a record has multiple child rows.

Frappe documents list capabilities including filters, sorting, and paging, and documents Query Reports with configurable columns and filters that are tied to a reference DocType for access control. These are useful capabilities to look for, not an assumption that every application exposes custom fields in the same ways. See Frappe’s List documentation: https://docs.frappe.io/framework/user/en/api/list.

Use a question from your weekly operating rhythm. For example: “Which active requests have a high-risk reason and no assigned owner?” If you cannot answer it reliably without manually opening records or exporting and repairing a spreadsheet, the proposed field design has not yet proved its value.

  • Filter records by each important custom field.
  • Sort by a date, numeric, or controlled-value field where relevant.
  • Build or inspect a report containing custom fields and relationship data.
  • Export a representative record set and inspect column names, values, and empty fields.
  • Check whether report and export permissions match your access policy.

Trace custom fields through APIs, imports, and connected applications

An integration can turn a well-designed field into a fragile dependency if its name, allowed values, permissions, or update behavior are unclear. Identify every route by which a representative record can be created or changed: the application interface, imports, a supported API, and any connected workflow you intend to use.

Frappe’s REST documentation describes selecting fields, filtering by conditions, sorting, and paginating records. Those documented behaviors illustrate an effective test: verify that your custom fields are returned when requested and can be filtered when needed. Separately, test any create, update, or delete behavior required by your integration against the official documentation and the version you plan to use. See Frappe’s REST API documentation: https://docs.frappe.io/framework/user/en/api/rest.

Bulk operations deserve their own test. ERPNext’s Data Import documentation says uploaded sheets are validated before import, warnings are presented by row or column and must be resolved before import, and successful imports are recorded in an import log. Whether or not your chosen application works this way, determine whether errors are found before business data is committed and whether the result is auditable. See ERPNext’s Data Import documentation: https://docs.frappe.io/erpnext/data-import.

  • Create a representative record through each required supported route.
  • Read it back and compare every custom value with the source.
  • Update one permitted field and confirm expected workflow effects.
  • Attempt an invalid update and inspect the error and resulting record state.
  • Test field selection, filtering, sorting, and pagination in the API if integrations need them.
  • Run a small import containing both valid and deliberately invalid rows.

Evaluate schema-change safety before you need it

Fields evolve. Teams rename categories, replace processes, and retire values. The essential question is not merely whether an administrator can make a change, but what happens to existing records, reports, integrations, and historical interpretation afterward.

Maintain a change register for each meaningful field: business purpose, owner, type, permitted values, default, validation, access policy, dependencies, and retirement approach. Before approving a change, identify which saved reports, imports, API consumers, and workflows reference it. Test the change on copies of representative records before applying it broadly.

Controlled values need particular care. Odoo’s ORM documentation describes an ondelete fallback for extended Selection options, including setting a value to null, cascading deletion, setting a default, assigning a specified replacement, or running custom processing. This is a useful decision pattern: when a value is retired, explicitly decide how records holding that value will be treated. Never let historical meaning become accidental. See Odoo’s ORM API documentation: https://www.odoo.com/documentation/19.0/developer/reference/backend/orm.html.

  • Rename a noncritical test field and inspect reports, exports, and integrations.
  • Attempt a field-type change using representative existing values.
  • Retire a controlled value and verify the treatment of existing records.
  • Document an approved replacement, null, or other retention approach for retired values.
  • Check whether finalized records require stricter change control.
  • Keep a record of schema decisions and their effective dates.

Frequently asked questions

What is the most important test when evaluating custom fields?

Build one realistic record model and follow it through the complete lifecycle: entry, validation, workflow, permissions, searching, reporting, export, import, and any required API integration. A field that works only on a form has not yet proved it is operationally useful.

Should every custom category be a dropdown or controlled value?

No. Use controlled values when consistency is needed for filtering, reporting, automation, or governance. Use free text when meaningful variation is expected and should not be forced into an artificial list. If the value is actually another maintained business object, test a relationship rather than a dropdown.

Why should we test API access to restricted fields?

Hiding a field in a user interface is not sufficient evidence that the underlying data is protected. Test a restricted user through every supported access route you plan to use, including APIs, reporting, exports, and imports, to verify that access controls are enforced.

What should we preserve during a migration?

Preserve stable record identifiers where the application uses them for updates, map relationships deliberately, and test attachments and repeating child rows separately. ERPNext documentation, for example, states that updates use the exported ID column and that removing a child-table row from an update file is treated as an intended deletion. Your target application may differ, so rehearse its actual behavior. See ERPNext’s Data Import documentation: https://docs.frappe.io/erpnext/data-import.

When is a configurable application the wrong choice?

Choose a purpose-built system or dedicated development when your core process depends on complex domain rules, specialized calculations, unusually strict regulatory controls, high-volume relationship handling, or a data model that cannot be represented and governed cleanly with the application’s supported structures. Configuration should reduce operational risk, not conceal a fundamental mismatch.

Sources and further reading

  1. Field Types — Frappe Framework
  2. DocField — Frappe Framework
  3. Child / Table DocType — Frappe Framework
  4. Users and Permissions — Frappe Framework
  5. REST API — Frappe Framework
  6. List — Frappe Framework
  7. Query Report — Frappe Framework
  8. Data Import — ERPNext
  9. Allow on Submit — Frappe Framework
  10. ORM API — Odoo