This is one of those tasks that should be simple but trips people up because the configuration is split across two places. You set part of it on the custom record type, and the other part on each role. Miss either one and the access control doesn't work the way you expect.

The good news: for most scenarios, no SuiteScript is required. NetSuite's native permissions handle it.

The Two Layers

Custom record access is controlled at two distinct levels:

  • The custom record definition sets the rules of the game. It determines the permission model and default access behavior.
  • Role permissions determine which roles can play. Each role gets a specific permission level for the record type.

Both layers must be configured correctly. The record definition without role permissions means nobody has access. Role permissions without the right record definition means everyone has access regardless of what you set.

Step 1: Configure the Custom Record Type

This is the foundation. Go to Customization → Lists, Records & Fields → Record Types and open the custom record type you want to restrict.

Look for the Access Type field. You have three options:

  • No Permission Required. Any logged-in user can access the record. Role-level restriction isn't possible. This is not what you want.
  • Require Custom Record Entry Permission. Access is controlled by role permissions. This is the one you want for role-based restriction.
  • Use Permission Level of Parent Record. Access inherits from a parent record's permission level. Useful for child records tied to transactions or entities.

Select "Require Custom Record Entry Permission." Without this, nothing you set on roles will have any effect.

While you're here, also review a few related settings: Allow UI Access (whether users can access the record through the interface), Show in Menu (whether it appears in navigation), and Allow Quick Search (whether it shows up in global search results).

Step 2: Assign Permissions on Each Role

Once the record type requires custom record entry permission, you grant access on a per-role basis.

  1. Go to Setup → Users/Roles → Manage Roles.
  2. Open the role you want to configure.
  3. Click the Permissions subtab, then the Custom Record sub-tab within it.
  4. Click Add and select your custom record type.
  5. Set the permission level.
  6. Save the role.

The permission levels are straightforward:

  • None. No access. The record is invisible to this role.
  • View. Can read records but not create or edit.
  • Create. Can create new records but not edit existing ones.
  • Edit. Can create and edit but not delete.
  • Full. Full access including delete.

Repeat for every role that should have access. Roles not explicitly granted permission will have no access at all when the record type is set to require it.

Step 3: Control Menu Visibility (Optional)

Restricting permissions prevents access, but users may still see the record type in menus if Show in Menu is enabled. To clean up navigation for restricted roles, use Custom Centers or Role-Based Navigation to control which menu items appear per role.

One important distinction: even if a menu link is visible, a role without permission will get an "Insufficient Permissions" error on access. Menu visibility is a UX concern, not a security control. Permissions are the security layer.

Step 4: Segment by Subsidiary (OneWorld Only)

If you're on OneWorld and want to restrict access by subsidiary in addition to role, enable "Allow per-subsidiary access" on the custom record type if available, and use subsidiary restrictions on the role itself under Setup → Users/Roles → Manage Roles → Subsidiaries subtab.

This works in conjunction with record-level permissions, not instead of them.

Advanced: Record-Level Permissions

Everything above controls access at the record type level. But what if you need row-level security, restricting which specific records a user can see within a type?

NetSuite supports this through Record-Level Permissions on custom records:

  1. On the custom record type, enable "Allow Record-Level Permissions."
  2. On individual record instances, a Permissions sublist appears.
  3. Assign specific roles or users with specific permission levels on that individual record.

This is useful when different teams should see different subsets of records of the same type, or when sensitive records within a type need tighter access than the rest.

A caveat: record-level permissions add administrative overhead at scale. Every record needs its permissions managed individually unless you automate it via SuiteScript. In practice, I'd recommend using this sparingly. Role-level permissions handle the majority of use cases.

Automating Record-Level Permissions with SuiteScript

If you need record-level permissions set automatically on create (for example, only the creating user's role can see the record), a User Event Script on afterSubmit can handle it:

/**
 * @NApiVersion 2.1
 * @NScriptType UserEventScript
 */
define(['N/record', 'N/runtime', 'N/log'], (record, runtime, log) => {

  const afterSubmit = (context) => {
    try {
      if (context.type !== context.UserEventType.CREATE) return;

      const currentUser = runtime.getCurrentUser();
      const roleId = currentUser.role;

      const rec = record.load({
        type: 'customrecord_your_record_type', // VERIFY: your record type ID
        id: context.newRecord.id,
        isDynamic: true
      });

      // VERIFY: confirm the permissions sublist ID and field IDs
      // in the Records Browser for your custom record type
      rec.selectNewLine({ sublistId: 'custrecord_permissions' });
      rec.setCurrentSublistValue({
        sublistId: 'custrecord_permissions',
        fieldId: 'role',
        value: roleId
      });
      rec.setCurrentSublistValue({
        sublistId: 'custrecord_permissions',
        fieldId: 'restriction',  // VERIFY: may be 'level' or similar
        value: 'EDIT'
      });
      rec.commitLine({ sublistId: 'custrecord_permissions' });
      rec.save();

    } catch (e) {
      log.error({ title: e.name, details: `${e.message} — ${e.stack}` });
    }
  };

  return { afterSubmit };
});

The permissions sublist ID and field names must be confirmed in the Records Browser under your specific custom record type. These aren't standard across all record types.

Which Approach to Use

  • All users of a role see all records, others see none. Role permissions on the custom record type. This is the most common scenario.
  • Some roles see all records, others see only their own. Role permissions as a baseline, plus record-level permissions.
  • Access varies by subsidiary. Role permissions plus subsidiary restrictions (OneWorld).
  • Access rules are dynamic and data-driven. Role permissions as a baseline, plus SuiteScript to manage record-level permissions automatically.
  • Hide the record from menus for restricted roles. Custom Centers or role-based navigation in addition to permissions.

Common Mistakes

I see these repeatedly in implementations:

Setting Access Type to "No Permission Required." This makes role permissions irrelevant. Anyone can access the record regardless of what you set on roles. Always use "Require Custom Record Entry Permission" for controlled access.

Forgetting to grant access to the Administrator role. Administrators typically have implicit access, but verify this in your account. Some configurations require explicit permission grants even for Administrators.

Relying on menu visibility as a security control. Hiding a menu link doesn't prevent access. A user who knows the URL can still reach the record if their role has permission. Permissions are the security control. Menu visibility is just UX.

Not testing with a non-Administrator role. Always test by logging in as, or impersonating, a user with the target role. Administrator roles often bypass restrictions that apply to other roles. If you only test as Admin, you haven't tested.

The Short Version

For most use cases, the native approach is three steps:

  1. Set Access Type = "Require Custom Record Entry Permission" on the custom record type.
  2. Grant the appropriate permission level on each role that should have access.
  3. Leave all other roles without a permission entry. They'll have no access by default.

Record-level permissions and SuiteScript automation are only needed when access must vary at the individual record level. Start with the native approach. It handles more than most teams expect.