How ERPNext field-level permissions with perm levels protect cost and margin
Perm levels let you hide or lock individual fields such as cost, margin or salary while the rest of a document stays visible to the same role. In ERPNext, each field on a DocType carries a permission level (perm level), and roles are granted read, write, create, submit, cancel or amend rights per level. A sales user can therefore open a sales order, see items, quantities and customer terms, and still be unable to see the valuation rate or margin columns that sit on a higher perm level. The situation that usually prompts this is a finance or HR lead who needs broad visibility into transactions without exposing the numbers that drive pricing decisions or pay.
Perm levels apply to the fields of a DocType, including fields inside child tables, and they work alongside the role permissions that govern the DocType as a whole. Level 0 is the default for every field. Higher levels are assigned to specific fields, and a role only sees or edits those fields if it holds a permission row for that level. Use this approach when a role should see the document but not particular values in it. If a role should not open the DocType at all, plain role permissions are the right tool. If the same field should be visible to some users with the full value and to others in a partially hidden form, that is a masking question, and the sibling topic on Frappe data masking covers it. Confirm the exact field and child table behavior on your ERPNext version, since the Frappe documentation describes the mechanism but edge cases in reports, exports and list views need testing on your own site.
Choosing between perm levels, user permissions and masking
Access in ERPNext is easiest to design when you separate three questions. The first is whether a role can open a DocType at all, which is governed by role permissions on the document. The second is which records a user can see once they have that access, which is governed by user permissions on link fields. The third is which field values a role can read or edit within a record they already open, which is governed by perm levels on individual fields. Most access mistakes come from answering one question with a tool built for another.
- Document access: Role permissions decide whether a role can read, write, create, submit, cancel or delete a DocType.
- Record scope: User permissions limit a user to records linked to specific values such as a company, territory or branch.
- Field scope: Perm levels control read and write rights on fields that share a level, for example cost or margin.
- Order of evaluation: A user needs document access first, then record scope, and field rules apply to what remains visible.
- Mixed cases: Sensitive values such as salary may need all three tools working together.
Confirm with your team which of the three questions each sensitive field actually raises before you choose a tool.
Perm levels group fields within a DocType into levels, usually starting at level 0. Each level has its own permission rows that assign read, write, create and other rights to roles. A role that has no rule for a level cannot see fields at that level, which lets you hide cost or margin on an otherwise shared document such as an item or sales order. Perm levels are set on the DocType in the customization interface, so they apply to every record of that type for every user with the matching role.
- Field-based: Use perm levels when the same DocType is shared but certain fields must be restricted for some roles.
- Role-based: Rights come from roles, not from the individual user or the record's owner.
- Not record-based: A perm level cannot hide a field only for some records, such as one company's margin.
- Shared across records: Changing a level affects all records of that DocType, so test on a copy of production data first.
- Standard roles: Check how existing standard roles already use levels before adding new rows.
Check whether the restricted field's value is also visible through reports, list views, exports or linked documents, since perm levels do not cover every path.
User permissions restrict which records a user can see based on the value of a link field. For example, a user restricted to one company sees only documents linked to that company, and a user restricted to one territory sees only related customers and orders. They work alongside role permissions: a user must still have a role that grants access to the DocType. They do not hide individual fields, so a user who can see a sales order in their company can still see every field on it that their roles allow.
- Record-based: Decide which records a user sees using a link value, not a field level.
- Per DocType: Each restriction applies to specific DocTypes, so check which ones are affected by the chosen link.
- Hierarchy: Managers may need access to their team's records, which requires designing the hierarchy on purpose.
- Blind spots: Records with an empty link value may behave differently from what you expect, so test them.
- Not a field tool: A user with broad record scope can still see restricted fields if a perm level does not hide them.
Write down the link field each restriction depends on, and confirm how your target version handles records where that field is empty.
Data masking is a separate topic and is not covered in depth here. It aims to show a partially hidden value, such as the last digits of a bank account, to some roles while others see the full value. Its availability and status depend on the ERPNext and Frappe version you run. Before you plan around it, confirm with the vendor documentation for your target version whether masking is available, whether it is experimental, and how it differs from perm levels. Do not assume a feature exists because a neighboring version has it.
- Display behavior: Masking changes how a value is shown, which can differ from whether it is stored or exported.
- Version dependency: Confirm the status for your exact target version before designing around it.
- Experimental status: If a feature is marked experimental, weigh that against your compliance and support needs.
- Compare with perm levels: Perm levels control access to the field, while masking controls how a permitted user sees part of the value.
- Separate design: Treat masking as its own decision with its own testing.
Ask your implementation team to show you masking behavior in a test environment on the version you will run before relying on it.
Choose the tool by the question each sensitive item raises. If a role should not open a DocType, use role permissions. If the same person should see only some records, use user permissions. If a shared record must hide certain fields from some roles, use perm levels. If a value must be partly shown, evaluate masking for your version. Many real designs combine two tools, such as perm levels on cost plus user permissions on company, so write the combined rule down before building it.
- Start with the data: List the sensitive fields and the records they live on.
- Match the question: Assign each field to the tool that answers its access question.
- Combine deliberately: Document which two or three tools together protect each sensitive item.
- Check reporting paths: Confirm that reports, exports and linked documents respect the same rules.
- Test each role: Verify what every role sees using test users on a copy of production data.
Before finalizing the design, ask your implementation partner to walk through each sensitive field and show which tool controls it in your environment.
Setting up perm levels on a DocType step by step
This sequence takes one sensitive field, such as cost or margin, from an open field on a DocType to a tested rule where only the intended roles can read or change it. Each step ends with a check so the team knows the configuration matches the access design before it reaches users.
Confirm the field and its access requirement
Before touching any configuration, the implementation lead lists each sensitive field, the DocType it sits on, and the roles that need to read it, edit it, or never see it. Write this as a short access matrix and get sign-off from the business owner of the data. The step is done when every field has a named owner and a list of roles, and no field is left with an undefined audience.
Set the perm level in the DocType customizer
An administrator opens the DocType customizer for the target DocType and sets a perm level value on each sensitive field, leaving standard fields at level 0. Keep the number of levels small so the matrix stays readable. Confirm the exact menu path on your installed version, since labels change between releases. The check is that the field properties show the new perm level and that the DocType preview lists the field under the right section.
Add role permission rows for each perm level
In the DocType's permission table, add a row for each role and each perm level that needs access, then tick the read, write, create, submit, cancel or amend flags only where the role needs them. Rows at level 0 control the rest of the document, so a role that can read a sensitive field also needs level 0 read access to open the record. The check is that the table, filtered by perm level, lists exactly the roles in your access matrix.
Save and clear the cache
Save the customized DocType and clear the site cache so the new permission rules apply to active sessions. Because the change alters a standard DocType, make it through the customizer or a custom app, not by editing core files, so the configuration can be exported and reapplied after upgrades. The check is that the save completes without errors and the customization appears in the change log or export that your team keeps under version control.
Create test users for each role
Create one test user per role in the access matrix on a non-production site, with no extra roles and no User Permission restrictions beyond what production will use. Use role profiles only if production uses them. The check is that each test user has exactly one role set, which the team can verify on the user record before logging in.
Verify what each role sees
Log in as each test user, open a record of the affected DocType, and compare the visible fields with the matrix. Check the list view, the report view, the print format, and the export, because a field hidden on the form can still appear in reports if a report role has read access. The step is complete when every role sees the expected values, and any mismatch is logged with the role, field and document used.
Test write and submit behavior
As each test user, try to edit the protected field and, where relevant, submit or cancel the document. Confirm that roles without write access receive a read-only field and that roles with write access can save without errors. This is also the point to confirm how the rule behaves on documents already in the system, since existing values remain as they are. The check is a short written result for each role that matches the access matrix.
Record the configuration and confirm the upgrade path
Export the customization, record the perm level assignments and role rows in the team's documentation, and list the test results alongside them. Ask the implementation partner or your internal team to confirm the steps for the installed ERPNext version, because menu labels and defaults can differ. The check is a repeatable procedure that a second administrator could follow on a fresh site and reach the same result.
How role rows and perm levels combine for each role
This table maps three sample roles against perm level 0 and a restricted perm level on a hypothetical Purchase Order DocType, showing read, write, create and submit flags. Read it as a pattern rather than a configuration to copy: a role sees a restricted field only when its permission row for that perm level grants read. The main takeaway is that a missing row for the restricted level hides the field, even when the role can edit the rest of the document.
| Role (illustrative) | Perm level 0: read, write, create, submit | Perm level 1 (restricted fields): read, write, create, submit | What the role sees in restricted fields |
|---|---|---|---|
| Sales user | Read, write, create, submit: yes, no, no, no | No row for perm level 1 | Hidden: cost and margin fields are not shown |
| Purchase manager | Read, write, create, submit: yes, yes, yes, yes | Read, write: yes, yes, no, no | Visible and editable, but cannot create new restricted rows |
| HR manager | Read, write, create, submit: yes, yes, yes, no | Read: yes, write: yes, create: no, submit: no | Salary-related fields visible and editable on existing records |
| System Manager | Read, write, create, submit: yes, yes, yes, yes | Read, write, create, submit: yes, yes, yes, yes | Full access, which is why this role should be limited |
| Auditor (read-only) | Read: yes, write: no, create: no, submit: no | Read: yes, write: no, create: no, submit: no | Restricted fields visible without any editing rights |
| Role with no matching row | Read: yes on standard fields | No row for perm level 1 | Hidden, regardless of other permissions on the DocType |
Testing what each role sees before go-live
Perm levels only work if each role sees exactly what its row allows, and the only reliable way to confirm that is to log in as each role and check every surface where the field can appear. The cards below cover the test cases to run, the staging setup they need, and the evidence to keep for review.
Set up one test user per role
Create a dedicated test user for every role that touches the sensitive DocType, and assign only the roles that a real employee in that job would hold. Avoid testing with Administrator or a System Manager account, because those accounts bypass the restrictions you are trying to prove. Record the role list for each user so the test results can be matched to the permission matrix later. Re-create the users after any role change, since a permission row that looks correct on paper can still be overridden by a user permission or a second role the test user carries.
Check the form view
Open a saved document as each test user and confirm that fields at the restricted perm level are hidden or read-only as designed. Include the fields that appear only after a status change, such as cost or margin fields that show on submitted documents. Try to edit a read-only field through the form and confirm the save is refused. Check the sidebar, comments and version history too, because a restricted value can leak through a timeline entry even when the field itself is hidden.
Check list and report views
Restricted fields often reappear in list view columns, sidebar filters, group-by counts and standard reports. Log in as each role, open the list for the DocType, and add or inspect columns and filters that reference the restricted field. Run the standard reports that draw on the same DocType, since report permissions are evaluated separately from form permissions. A value that a role cannot read on the form but can filter on in a list can still reveal its contents by trial and error, so test filters as well as columns.
Check print formats and exports
Print formats and data exports are the most common gaps in a field-level design. Generate the print format for each role and check whether the restricted value appears in the header, totals, or attached templates that were copied from another site. Then run the Data Export tool and the list export as each role, and confirm the restricted columns are absent from the file. Repeat the check for any email sent from a document, because the rendered print format is often attached automatically.
Check API responses and child tables
Call the REST endpoints for the DocType with each test user's API key or session and inspect the returned JSON for restricted fields. A field that is hidden in the UI may still appear in a response if the permission check was not applied to that path. Test child tables separately, because a restricted field inside an item row or a timesheet row may be exposed even when the parent document is locked for that role. Keep the request and response pairs as evidence.
Record the evidence and retest
Keep a dated test log that lists each role, test user, DocType, surface tested, expected result and actual result, with screenshots or saved responses where the result matters. Run the full matrix on the staging site with production-like data and roles, since permissions behave differently with real volumes and customizations. Repeat the matrix after every upgrade, custom field addition or new role assignment, and ask your team to confirm which evidence the auditor expects to see before you start.
Security and operational risks of field-level rules
Field-level permissions only protect data on the screen they govern. The risks below are the paths around that screen, and the changes over time that quietly reopen them. Review each one as part of every role change and upgrade.
Leaks through reports and exports
A locked field on the form can still appear in a Report View, Query Report, or a data export if the role can open that report or list. Check which reports and list views include cost, margin or salary columns, and confirm the role's report access before assuming the field is hidden. Run each sensitive report as a test user in the restricted role and compare the output with the form.
Exposure through API endpoints
Permissions enforced in the desk UI also apply to the REST API, but an integration user with broad read rights can return every field of a document, including those hidden in the form. Audit API keys and integration users, and list which DocTypes they can read. Avoid running integrations under System Manager or Administrator accounts.
Print formats and attachments
Print formats render fields from the document regardless of what the viewer sees on screen, so a restricted user who can print or email a document may receive cost figures. Review the print formats attached to each DocType and remove sensitive fields from any format sent to outside parties. Check attachments and linked files as well, since they are not governed by perm levels.
Linked documents reveal values
A user who cannot read a sensitive field may still see it through a linked document, a child table shown in another form, or a dashboard that aggregates totals. Map the links from each sensitive DocType and test whether a restricted role can reach the values through a related record. Hide or restrict the linked DocType where the value must stay private.
Role sprawl undoes field locks
Each new role or added permission row can widen access to a field that was previously locked, especially when a user holds several roles and ERPNext applies the most permissive combination. Limit which users can assign System Manager, review role profiles against job functions, and check the effective permissions of any user who gained a role. Small role changes over time often cause more exposure than the original design.
Drift after upgrades and customizations
Custom fields, scripts and app changes can add new sensitive fields without perm levels, and an upgrade can alter defaults or the DocTypes an app ships. Re-test the role matrix after each ERPNext or custom app upgrade, and treat new custom fields as unprotected until a reviewer sets their permissions. Keep the role matrix in version control so that changes can be compared and reversed.
Questions teams ask before configuring field-level permissions
Can our own team configure perm levels in ERPNext without a partner?
Yes, a team with a working ERPNext site and an administrator who understands roles can set perm levels on DocType fields in the Customize Form tool and in the DocType permission tables. The work itself is small per field. The risk sits in the role matrix: a field set to a higher perm level is hidden or read-only for every role that lacks a matching permission row at that level, so a mistake can block users from entering data they need. Teams without a documented role matrix and a staging site usually find the second and third passes take longer than the first.
What drives the effort for field-level permissions?
Effort scales with the number of DocTypes that carry sensitive fields, the number of roles that touch those DocTypes, and the reports, print formats, dashboards and integrations that read the same fields. Each DocType with a cost, margin or salary field needs its permission rows reviewed for every role, and each report that exposes those fields needs its own check. Custom scripts or API integrations that read restricted fields add another review, because permission rules on the desk do not automatically govern every code path. Ask any provider to list the DocTypes, roles and integrations in scope before agreeing a number.
How long does testing take for a field-level permission change?
Testing length depends on how many roles and sensitive fields you have, and how many test users you can set up on a non-production site. A small change to one DocType and two roles is a short test cycle. A change that spans sales, purchasing, stock and payroll roles means testing each role against create, read, write, submit and cancel actions, plus reports and exports. Ask for the test scope in writing: which roles, which DocTypes, which reports, and whether the test includes integrations and API access.
What must we provide before field-level permission work starts?
Three things make the work predictable. First, a role matrix that lists each role, the DocTypes it uses, and the fields it may see, edit or never see. Second, sample users for each role, with realistic but non-production data, so every role can be tested as it will really work. Third, a staging site on the same ERPNext version as production, with a recent copy of the data or representative test records. Without a staging site, changes are tested in production, which makes rollback and user communication harder.
Does a fixed-scope engagement cover field-level permission configuration?
A fixed-scope engagement can cover it when the scope, deliverables and timeline are agreed in writing before work starts. Typical written items are the DocTypes and fields in scope, the roles and sample users used for testing, the test cases and their results, and the handover documentation. Anything outside that list, such as new roles, extra reports, or custom scripts that touch restricted fields, should be added through a written change to scope. DeployOpen does not publish a price list, so the quote follows from the written scope.
What recurring work follows ERPNext upgrades for permissions?
Each ERPNext or Frappe upgrade can change standard DocTypes, add fields, or alter how permissions apply, so the permission matrix needs a regression pass after every upgrade. The Frappe supported versions page lists which major versions are supported and when each reaches end of life, which sets the pace for planning those passes. ERPNext also receives frequent minor releases on GitHub, so teams should decide whether to apply them on a set cadence. Ask your provider whether the retainer covers permission regression tests after upgrades and whether new roles or DocTypes trigger a scope change.
Is there a risk that field-level permissions expose data through other paths?
Yes. Perm levels control what a role sees on the form, but reports, list views, exports, API responses and server scripts can read fields through other paths. Server Scripts in version 15 and later are disabled by default and must be enabled through the server_script_enabled setting, so confirm whether they are on in your site before assuming coverage. Check each report and integration that reads sensitive fields, and test API access with a user from each role. Treat field permissions as one control in a wider access model, not a complete one.
How DeployOpen scopes and delivers field-level access work
Every engagement starts with a written scope that names the sensitive fields (cost, margin, salary or similar), the roles that should see or edit each one, and the test cases that will prove the result. Before any configuration, the team agrees which DocTypes are involved, which fields carry a perm level, and which roles hold read, write, create or submit rights at each level. This list is the working contract. It also tells you where the rules are hard to get right, such as a field that appears on several DocTypes, a child table that carries the same value, or a report that exposes the figure in a total. Most engagements are fixed-scope, so the scope, deliverables and timeline are agreed in writing before work begins, and changes to the field list are handled as a written change to that scope.
Configuration then happens on a staging site, not on production. DeployOpen assigns perm levels, adjusts the role rows and runs each test case as each role in the agreed matrix, then produces a role-by-field test record showing what every role sees and can change. Ask for that record in a form your reviewers can re-run, and confirm that the test accounts reflect the roles your users really hold, including any roles inherited through role profiles or LDAP group mapping. The record documents configuration and testing. It is not an audit report, an attestation or a certification, and it does not replace an assessment by an independent auditor or certification body. If your controls must be evidenced for an external review, confirm with your auditor which artifacts they will accept.
Ongoing support is available as a retainer. Permissions drift as new fields, reports and custom apps are added, and as ERPNext releases change behavior, so a retainer can cover re-running the role-by-field tests after upgrades, reviewing new custom fields for sensitivity and handling access requests. Ask whether a quote separates the one-time build and testing from recurring review, and what triggers a re-test.

