Total Pageviews

Apex, LWC,

Apex User Mode vs System Mode: What Changed in Salesforce?

Apex User Mode vs System Mode: What Changed in Salesforce?

When we write Apex code, we usually focus on getting the work done. We write a SOQL query, update a record, and return the result to the user. But there is one important question we should ask: Does the current user have permission to access or update this data?

Salesforce has its own security model. A user may be able to open an Account record but may not have permission to view a particular field. Another user may not have access to that Account at all.

This is where Apex User Mode and System Mode come into the picture.

Salesforce introduced user-mode database operations to make it easier for developers to enforce security directly in Apex. More recently, API version 67.0 introduced a major change: database operations now run in User Mode by default for that API version, rather than System Mode.

In this blog, we will understand both modes, look at practical Apex examples, and discuss what developers need to know before using these features in their projects.

1. What Is System Mode in Apex?

By default, Apex database operations in older API versions run in System Mode unless you specify another access mode.

In System Mode, Salesforce does not enforce the current user's object permissions and field-level security in the same way it does in User Mode. This means Apex can read or modify fields that the running user would not normally be allowed to access through the Salesforce interface.

For example, suppose a sales user can view an Account but cannot edit the Annual Revenue field. If Apex updates that field using System Mode, the operation can succeed even though the user does not have field-level edit permission.

This can be useful for trusted backend processes, but it can also create a security problem if the code allows users to change data they should not be able to change.

Important: System Mode does not automatically mean that every record is accessible. Record-level sharing still depends on the sharing behavior of the Apex class or other applicable security controls.

Example: Querying an Account in System Mode

List<Account> accounts = [
    SELECT Id, Name, AnnualRevenue
    FROM Account
    WITH SYSTEM_MODE
];

This query explicitly requests System Mode. It bypasses the running user's object-level and field-level permission checks for this query. Record visibility still depends on the applicable sharing behavior.

Using System Mode should always be a deliberate decision. Do not use it just because a query is throwing a permission error.

2. What Is User Mode in Apex?

User Mode allows a database operation to respect the current user's security permissions.

When a query runs in User Mode, Salesforce checks the applicable permissions, including:

  • Object permissions: Can the user read the Account object?
  • Field-level security (FLS): Can the user access the Annual Revenue field?
  • Record-level access: Can the user access the particular Account record?

User Mode also enforces other applicable access controls, such as restriction rules where relevant.

If the user does not have the required permission, the operation can fail with a security exception. That is expected behavior, not necessarily a problem with the Apex code.

Example: Querying an Account in User Mode

List<Account> accounts = [
    SELECT Id, Name, AnnualRevenue
    FROM Account
    WITH USER_MODE
];

Here, Salesforce checks whether the current user is allowed to read the Account object, access the selected fields, and view the matching records.

If the user does not have permission to read Annual Revenue, the query can fail even if the user has access to the Account records themselves.

This is useful when an Apex controller returns data to an LWC, Aura component, or another feature that should respect the current user's permissions.

3. What Changed in Salesforce?

For a long time, Apex developers had to pay special attention to CRUD permissions, field-level security, and record sharing because Apex database operations traditionally ran in System Mode by default.

Developers could use class sharing declarations, describe methods, and security utilities to control access. However, developers had to make sure the appropriate checks were included in the code.

Salesforce later introduced explicit User Mode database operations, including SOQL access-mode clauses and DML syntax. This gave developers a more direct way to enforce security at the database-operation level.

Now there is another important change to understand.

The API version 67.0 change

Starting with API version 67.0, Salesforce changed the default behavior of Apex database operations to User Mode. In earlier API versions, the default was System Mode.

Here is the simple comparison:

API version Default database operation mode
66.0 and earlier System Mode
67.0 and later User Mode

This is a versioned change. It does not mean that System Mode has been removed or that every existing Apex class automatically starts using the new default. The API version of the relevant code matters.

Salesforce also removed the WITH SECURITY_ENFORCED SOQL clause in API version 67.0. For new code, use WITH USER_MODE when you want the query to enforce the current user's access permissions.

One practical recommendation: explicitly declare the intended access mode in your database operations. This makes the code easier to understand and reduces confusion when working with classes that use different API versions.

4. User Mode vs System Mode: Key Differences

Feature User Mode System Mode
Object permissions (CRUD) Enforced Not enforced for the operation
Field-level security (FLS) Enforced Not enforced for the operation
Record-level sharing Enforced Depends on the class sharing behavior
Missing permissions Operation can fail CRUD/FLS restrictions of the running user do not block the operation
SOQL syntax WITH USER_MODE WITH SYSTEM_MODE
DML syntax insert as user insert as system
Typical use User-facing features that must respect permissions Trusted backend operations that intentionally need elevated access

Remember that the mode controls the database operation. It does not mean the entire Apex class permanently changes its execution mode.

5. Practical Example Using the Account Object

Let's take a simple example. We have an Account with the following details:

  • Account Name: ABC Technologies
  • Annual Revenue: ₹50,00,000
  • The user can read the Account record.
  • The user does not have permission to edit the Annual Revenue field.

Now suppose we want to update Annual Revenue through Apex.

Example A: Updating Annual Revenue in User Mode

public with sharing class AccountRevenueController {

    public static void updateRevenue(Id accountId) {

        Account acc = [
            SELECT Id, AnnualRevenue
            FROM Account
            WHERE Id = :accountId
            WITH USER_MODE
        ];

        acc.AnnualRevenue = 7500000;

        update as user acc;
    }
}

What happens here?

The query checks the user's permission to access the Account and the Annual Revenue field. If the user can read the field and access the record but cannot edit Annual Revenue, the query may succeed while the update fails.

The update runs in User Mode, so Salesforce checks the user's update permission on the Account object and edit permission on Annual Revenue. If the required permission is missing, the update fails.

In this example, the user needs both read access for the query and the appropriate update permissions for the DML operation.

Example B: Updating Annual Revenue in System Mode

public with sharing class AccountRevenueService {

    public static void updateRevenue(Id accountId) {

        Account acc = [
            SELECT Id, AnnualRevenue
            FROM Account
            WHERE Id = :accountId
            WITH SYSTEM_MODE
        ];

        acc.AnnualRevenue = 7500000;

        update as system acc;
    }
}

What happens here?

The query and update explicitly use System Mode. The user's CRUD and FLS permissions do not block these operations.

However, the class is declared with sharing. This means record-level sharing still applies to the query and, in the applicable sharing context, the DML operation. System Mode does not automatically give the code access to every record in the organization.

Also, the code should not be exposed to users without proper authorization. For example, if this method is called from an LWC, validate whether the current user is actually allowed to request the revenue update.

The main difference is simple: User Mode respects the user's field permissions, while System Mode allows the operation to bypass those CRUD/FLS checks.

6. How to Use User Mode and System Mode in DML

Salesforce provides two straightforward ways to choose an access mode for DML operations.

Using DML keywords

Account acc = new Account(
    Name = 'ABC Technologies'
);

// Enforce the running user's permissions
insert as user acc;

The insert succeeds only if the required user permissions and other applicable access controls allow it.

For an operation that intentionally needs System Mode:

Account acc = new Account(
    Name = 'ABC Technologies'
);

// Explicitly bypass the running user's CRUD/FLS checks
insert as system acc;

This operation does not require the running user to have Account create permission or permission to edit each supplied field. Other platform requirements, validation rules, required fields, and applicable record-sharing behavior still matter.

Use this syntax only when elevated access is appropriate for the business requirement.

Using Database methods with AccessLevel

You can also select the access mode through the Database class. This is especially useful when you want to use methods that return results for individual records.

Account acc = new Account(
    Name = 'ABC Technologies'
);

Database.SaveResult result = Database.insert(
    acc,
    AccessLevel.USER_MODE
);

if (result.isSuccess()) {
    System.debug('Account created: ' + result.getId());
} else {
    System.debug('Account creation failed');
}

Here, the insert uses User Mode. If the user lacks a required permission, the result can contain an error rather than the record being inserted.

For System Mode, change the access level:

Database.SaveResult result = Database.insert(
    acc,
    AccessLevel.SYSTEM_MODE
);

The Database methods are useful when you need to inspect individual success or failure results, such as during bulk operations.

7. Using Access Modes with Dynamic SOQL

Sometimes we build a query dynamically instead of writing a static SOQL query. For example, a search screen may allow users to filter Accounts by name.

In this situation, you can pass an access level to Database.query().

String accountName = 'ABC Technologies';

String queryString =
    'SELECT Id, Name FROM Account ' +
    'WHERE Name = :accountName';

List<Account> accounts = Database.query(
    queryString,
    AccessLevel.USER_MODE
);

This query executes in User Mode and enforces the applicable object permissions, field permissions, and record-level access rules.

If you intentionally need System Mode, use:

List<Account> accounts = Database.query(
    queryString,
    AccessLevel.SYSTEM_MODE
);

Always use bind variables for user-supplied values rather than directly joining those values into the query string. Choosing User Mode does not automatically prevent SOQL injection.

8. Understanding CRUD, FLS, and Record-Level Sharing

Before writing secure Apex, it helps to understand these three security layers.

CRUD: Object-Level Permissions

CRUD stands for Create, Read, Update, and Delete. These permissions control what a user can do with an object.

For example, a user may have read access to Account but may not have permission to create new Accounts.

FLS: Field-Level Security

FLS controls whether a user can view or edit a particular field.

For example, a user may be able to view an Account but not view Annual Revenue. Another user may be able to view Annual Revenue but not edit it.

Record-Level Sharing

Record-level access determines which individual records a user can access.

For example, a sales representative may have access to Accounts assigned to their team but may not have access to Accounts owned by another team.

These security layers solve different problems. A user may have permission to read the Account object but still be unable to access a particular Account record or a specific field.

9. User Mode vs with Sharing, without Sharing, and inherited Sharing

This is one of the areas where Salesforce developers can get confused. The access mode and the class sharing declaration are related, but they are not the same thing.

with sharing

The with sharing keyword enforces record-level sharing rules for operations that follow the class sharing context. It does not, by itself, enforce CRUD or FLS.

public with sharing class AccountController {
    // Record-level sharing is enforced
    // CRUD/FLS still needs to be handled
}

without sharing

The without sharing keyword allows the class to bypass the normal record-level sharing restrictions for operations that follow its sharing context.

public without sharing class AccountService {
    // Record-level sharing can be bypassed
}

Use it carefully. A class that bypasses sharing can expose records that the current user cannot normally access.

inherited sharing

The inherited sharing keyword allows the class to follow the sharing context of its caller. It can make the intended behavior clearer when the same service is called from different entry points.

public inherited sharing class AccountService {
    // Uses the caller's sharing context
}

What happens when User Mode is used?

When a database operation explicitly runs in User Mode, Salesforce enforces the user's applicable record access, object permissions, and field-level security. User Mode overrides the calling class's sharing declaration for that operation.

When a database operation explicitly runs in System Mode, CRUD and FLS checks for the running user are bypassed, while record-level sharing follows the applicable class sharing behavior.

For example, a without sharing class can still execute a query with WITH USER_MODE. That query enforces the current user's record access even though the class itself is declared without sharing.

One more thing to remember: the default sharing behavior can depend on the entry point, class declaration, and API version. Explicit class declarations and explicit database access modes make the code easier to review.

10. Common Mistakes Salesforce Developers Make

Mistake 1: Thinking with sharing enforces FLS

This is incorrect. The with sharing keyword controls record-level sharing, not object permissions or field-level security. Use User Mode or another appropriate CRUD/FLS enforcement approach.

Mistake 2: Assuming System Mode means access to every record

System Mode bypasses the running user's CRUD and FLS checks for the operation. Record-level sharing still depends on the applicable sharing context. Do not confuse the two.

Mistake 3: Using System Mode to fix permission errors

A permission error may indicate that the application is trying to perform an action the user should not be allowed to perform. Before switching to System Mode, check the business requirement and security design.

Mistake 4: Ignoring API version differences

The default behavior changed in API version 67.0. When maintaining older code or upgrading a class, check its API version and test its database operations.

Mistake 5: Forgetting field permissions during updates

A user may have access to a record but may not have edit permission for a particular field. User-mode DML checks these permissions and can reject the update.

Mistake 6: Assuming every query returns an empty list when access is denied

A User Mode query can throw a query exception when the user lacks required object or field permissions. It does not simply return an empty list in every permission-related situation.

11. When Should You Use User Mode?

Use User Mode when the database operation should respect the current user's permissions.

Some common examples include:

  • Reading Account records from an LWC component.
  • Showing Contact details on a user-facing screen.
  • Updating records based on a user's input.
  • Building search screens that should return only accessible data.
  • Creating or updating records while enforcing the user's CRUD and FLS permissions.

For most user-facing operations, User Mode is a good starting point because it makes the security requirement clear.

12. When Should You Use System Mode?

System Mode is useful when a trusted business process must perform a database operation regardless of the running user's CRUD or FLS permissions.

For example, an approved backend process may need to update an internal status field that regular users cannot edit.

However, using System Mode should not be a shortcut for avoiding security configuration. The application must still validate who can start the process, which records can be affected, and what data can be changed.

When appropriate, use a narrowly scoped service, validate inputs, restrict access to entry points, and document why elevated permissions are needed.

13. Best Practices for Secure Apex Code

  • Use WITH USER_MODE for queries that should respect the current user's permissions.
  • Use insert as user, update as user, and similar DML syntax when user permissions must be enforced.
  • Use AccessLevel.USER_MODE with supported Database methods when appropriate.
  • Specify System Mode explicitly when a trusted operation genuinely requires elevated access.
  • Do not rely on with sharing alone to enforce CRUD and FLS.
  • Use bind variables when building dynamic SOQL.
  • Handle permission-related exceptions and return useful error messages to the user.
  • Test Apex with users who have different profiles, permission sets, field permissions, and record access.
  • Review API versions when upgrading existing classes.
  • For features that only need ordinary record access, consider Lightning Data Service before writing custom Apex.

14. Frequently Asked Interview Questions

Q1. What is the main difference between User Mode and System Mode?

User Mode enforces the current user's CRUD, FLS, and applicable record-level access. System Mode bypasses the user's CRUD and FLS checks for the operation, while record-level sharing depends on the applicable sharing context.

Q2. Does with sharing enforce field-level security?

No. It enforces record-level sharing. CRUD and FLS must be enforced separately, for example by using User Mode.

Q3. What is WITH USER_MODE in SOQL?

It is a SOQL clause that makes the query enforce the applicable security permissions of the current user.

Q4. What is AccessLevel.USER_MODE?

It is an access-level value that can be passed to supported Database and Search methods to run the operation in User Mode.

Q5. Can a query in User Mode fail if a field is inaccessible?

Yes. If the query selects or otherwise uses a field the user is not allowed to access, Salesforce can throw a query exception.

Q6. What changed in API version 67.0?

Database operations now run in User Mode by default for API version 67.0 and later. Earlier API versions defaulted to System Mode. The WITH SECURITY_ENFORCED clause was also removed in API version 67.0.

Q7. Can we use User Mode inside a without sharing class?

Yes. An explicitly user-mode database operation enforces the user's record access and CRUD/FLS permissions, even if the calling class is declared without sharing.

15. Final Thoughts

User Mode and System Mode are not just two different ways to write Apex queries. They help determine whether database operations respect the current user's permissions.

Earlier, developers had to pay close attention to security checks because Apex database operations generally ran in System Mode by default. Salesforce has made security easier to express through User Mode operations, and API version 67.0 takes this further by making User Mode the default for database operations.

My recommendation is simple: choose the access mode based on the business requirement instead of relying on defaults. Use User Mode for user-facing operations that should respect the user's permissions. Use System Mode only when elevated access is genuinely required and properly controlled.

Understanding this difference will help you write Apex code that is easier to maintain and safer to use in real Salesforce projects.

If you are preparing for Salesforce developer interviews, make sure you understand the difference between CRUD, FLS, sharing rules, and database access modes. These concepts often come together when designing secure Apex applications.

Thanks for reading KhumedSFDC. Keep learning, keep coding, and keep building!

References