Docs/Reference

Reference

Look up supported Salesforce metadata, profiles, permissions, and platform surfaces.

References

Salesforce Profiles

Profiles are a legacy Salesforce concept - they define permissions per object and field and are assigned to every user. Unlike most metadata, they are not deployable as discrete records and they live in a separate namespace from permission sets.

Nimbus models Profile as a standard SOQL-queryable object backed by a local database table. A set of standard profiles is always seeded so common test patterns work out of the box:

Profiles in Nimbus are lookup-only. Nimbus does not enforce profile-based object or field permissions (FLS/CRUD). Tests run with full data access regardless of which profile the running user is assigned to. Field-level writeability comes from synced schema metadata (nimbus sync), not from profile assignments.

FlagDefaultDescription
System Administrator00e000000000002AAAStandard user type, Salesforce license
Standard User00e000000000003AAAStandard user type, Salesforce license
Read Only00e000000000005AAAStandard user type, Salesforce license
Chatter External User00e000000000004AAACsnOnly user type, Chatter External license
Minimum Access - Salesforce00e000000000006AAAStandard user type, Salesforce license

Running user profile

Every test runs as a mock user (ID 005000000000000AAA). The profile assigned to that user - what UserInfo.getProfileId() resolves to - defaults to Standard User. Override it with nimbus.mock.user-profile.

This matters when your code branches on the running user's profile name, e.g.:

apex
// Example: trigger framework checking profile to decide whether to fire
String profileName = profileMapById.get(UserInfo.getProfileId()).Name;
if (profileName == 'My Profile') { return; }
bash
# nimbus.properties
nimbus.mock.user-profile=My Profile

Project-specific profiles

If your tests query for profiles not in the built-in set, seed them with nimbus.seed.profiles. Comma-separated list of profile names. Seeded profiles get a deterministic ID and are assigned Standard user type with the Salesforce license - sufficient for the vast majority of test patterns.

bash
# nimbus.properties
nimbus.seed.profiles=Field Sales,Partner Community

These profiles are then findable via SOQL:

apex
Profile p = [SELECT Id FROM Profile WHERE Name = 'Field Sales' LIMIT 1];
User u = new User(profileId = p.Id, ...);

Default record types

In Salesforce, records inserted without an explicit RecordTypeId get the running user's profile default. Nimbus defaults to the Master record type. If your org uses custom record types and flows or triggers branch on RecordTypeId, configure per-object defaults:

bash
# nimbus.properties
nimbus.default-record-type.Lead=Applicant_Record_Type
nimbus.default-record-type.Case=Support_Case

List views

Nimbus auto-discovers .listView-meta.xml files from your project and seeds them into the database. For standard object list views that aren't in your repo (Salesforce includes built-in views like "All Leads"), seed them via config:

bash
# nimbus.properties — format: nimbus.seed.list-view.<Object>.<DeveloperName>=<Label>
nimbus.seed.list-view.Lead.AllLeads=All Leads
nimbus.seed.list-view.Lead.MyLeads=My Leads
nimbus.seed.list-view.Case.AllCases=All Cases

Standard reference data

Some standard objects are org-managed reference data that always exists on a real org but isn't carried by nimbus sync(which brings schema, not rows). Nimbus seeds the common ones with their standard out-of-box values so test-setup idioms that read them work without per-repo stubs:

FlagDefaultDescription
OpportunityStage10 stagesStandard sales process — Prospecting … Closed Won / Closed Lost, with IsClosed / IsWon / DefaultProbability / ForecastCategory
TaskStatus6 statusesNot Started, In Progress, Completed, …
CaseStatus4 statusesNew, Working, Escalated, Closed
BusinessHoursDefault rowThe always-present "Default" business hours record

These match a default org. If your org customises the picklist (e.g. custom opportunity stages), the seeded labels may differ from your StageName values — seed the records you need explicitly with nimbus.seed.record (below) to override.

Tabs (Schema.describeTabs())

Schema.describeTabs() returns a single tab set whose tabs are read from your project's *.tab-meta.xml (CustomTab) metadata — source-driven, like the rest of the schema. An object tab resolves its getSobjectName() and label from the object; web/VF/Lightning tabs carry their own label. Code that resolves a tab or icon for an SObject finds it; a project with no tab metadata gets a present-but-empty set.

Named SObject records (list custom settings)

List Custom Settings are accessible in real Salesforce tests as org-level data. In Nimbus, the local database starts empty, so code that reads them via CustomSetting__c.getAll() gets nothing. Seed the records you need with nimbus.seed.record:

bash
# nimbus.properties — format: nimbus.seed.record.<Object>.<Name>=<Field=value,...>
nimbus.seed.record.CountryCodeSetting__c.de=Land__c=Deutschland,Liefergebiete__c=Berlin
nimbus.seed.record.CountryCodeSetting__c.nl=Land__c=Niederlande,Liefergebiete__c=Amsterdam

The Name in the key becomes the record's Name field. Existing records (same name) are skipped, so tests that insert their own records during @testSetup are unaffected.

Sites

Code that queries Site or SiteDetail (e.g. SELECT Id FROM Site WHERE Name = '...') will find no rows unless you seed them via config:

bash
# nimbus.properties — format: nimbus.seed.site.<Name>=<secureUrl>
nimbus.seed.site.My Portal=https://myportal.my.site.com
nimbus.seed.site.Partner Community=https://partners.my.site.com

Each entry inserts a Site row (status Active) and a matching SiteDetail row with the given secure URL. IDs are generated deterministically from the name so they are stable across runs.

Public Groups

Standing Public Groups (regional or team groups like Sales - EMEA or Support Tier 1) are usually created once by an admin and never checked into repo metadata. Code that queries them by name — often user-trigger automation that adds users to groups on country/team change — comes up empty in Nimbus. Seed them via config:

bash
# nimbus.properties — format: nimbus.seed.group.<Name>=<Type>
# Type defaults to "Regular" when omitted
nimbus.seed.group.Sales - EMEA=Regular
nimbus.seed.group.Support Tier 1=Regular

Each entry inserts a Group row with a deterministic 00G-prefix Id from the name. The key is written to both Name and DeveloperName — test factories that look groups up either way (WHERE Name = 'X' or WHERE DeveloperName = 'X') resolve the same row. Idempotent across runs.

Queues

Queues are Group rows with Type='Queue' plus QueueSobject children mapping each queue to the SObjectTypes it routes. Case/lead/custom assignment automation looks them up by DeveloperName and joins through QueueSobject to find owner candidates. Seed both halves in one entry:

bash
# nimbus.properties — format: nimbus.seed.queue.<DeveloperName>=<SObject1>,<SObject2>
nimbus.seed.queue.Lead_Triage_DE=Lead,Case
nimbus.seed.queue.High_Value=Opportunity

Each entry inserts a Group row (Type=Queue) plus a QueueSobject row per listed SObjectType. Empty value still creates the queue Group row without any routing rows.

UserRoles

Role-hierarchy lookups and user-factory routines that assign UserRoleId need rows to exist; UserRole metadata is rarely checked into the repo. Seed by DeveloperName with the human label as the value:

bash
# nimbus.properties — format: nimbus.seed.role.<DeveloperName>=<Name>
# Value defaults to the DeveloperName when omitted
nimbus.seed.role.EMEA_Manager=EMEA Manager
nimbus.seed.role.APAC_Sales=APAC Sales

When at least one role is seeded the built-in CEO mock UserRole steps aside — WHERE DeveloperName = '...' and other clauses run against the real seeded rows. Tests that don't seed any role still receive the mock for backward compatibility.

Networks (Experience Cloud)

Code that gates on a community resolves it by name — [SELECT Id FROM Network WHERE Name = 'Member Hub']. The Network object is org-resident and rarely checked into repo metadata. Seed by Name; the value is the Status (defaults to Live):

bash
# nimbus.properties — format: nimbus.seed.network.<Name>=<Status>
nimbus.seed.network.Member Hub=Live
nimbus.seed.network.Partner Portal=UnderConstruction

Named Users

Factories that look up integration or system users by name — [SELECT Id FROM User WHERE Name = 'System Salesforce'] — need those rows to exist. Seed by the full Name; the value is an optional Username (derived from the Name when omitted):

bash
# nimbus.properties — format: nimbus.seed.user.<Name>=<Username>
nimbus.seed.user.System Salesforce=
nimbus.seed.user.Integration Bot=integ.bot@example.com

The seed Name is split on the first space into FirstName / LastName so the generated Name field reconstructs exactly.

Pulling setup data from the org

Instead of hand-editing seed entries for every Group/Queue/UserRole/Network the tests rely on, run sync with --include-setup-data to populate them from the connected org:

bash
nimbus sync --include-setup-data

The command queries the org for Group, QueueSobject,UserRole, and Network rows and writes the matching nimbus.seed.{group,role,queue,network}.* entries into nimbus.properties under a delimited block. Re-running refreshes the block; hand-authored seed lines outside the block are preserved. Named Users are not bulk-synced — a large org has thousands — so seed them explicitly with nimbus.seed.user.<Name>.

Each object type is pulled independently. If the org can't query one — an org without Experience Cloud has no queryable Network, for example — that type is skipped with a warning and the rest still land. The pull only fails outright when no setup object can be queried at all (usually a bad org alias or no connection).

Pulling permission sets from the org

Most orgs grant object access through permission sets rather than profiles. If your tests build a user, assign a permission set or permission set group, and then query under WITH USER_MODE or inside System.runAs, nimbus needs to know what those grants contain:

bash
nimbus sync --include-permissions

This pulls PermissionSet, their ObjectPermissions and FieldPermissions, and PermissionSetGroup composition into .nimbus/permissions.json, which the test runner seeds before each run. Profile-owned rows are excluded — every profile has a shadow permission set on the platform, and nimbus models profiles separately through their default footprint.

Permission sets defined in your own project metadata always win: local .permissionset-meta.xml files are loaded after the synced data, so the repo stays the source of truth and the sync only fills what isn't checked in.

Without this, a permission set group whose contents nimbus has no record of is treated as unknown rather than empty, and access is left unrestricted — better a missed denial than failing a test that passes in the org. Once permissions are synced, groups are enforced for real.

Custom Label overrides

Some repos ship Custom Labels with placeholder values (PLACEHOLDER,TBD) that admins replace post-deploy with environment-specific IDs — profile Ids, webhook URLs, signing keys. Tests that branch onLabel.X resolve to the repo value in Nimbus and diverge from prod. Override them at runtime:

bash
# nimbus.properties — format: nimbus.seed.label.<FullName>=<value>
nimbus.seed.label.StandardUserProfileId=00e000000000003AAA
nimbus.seed.label.WebhookEndpoint=https://test.example.com/hook

The override wins over any value parsed from .labels-meta.xml files and over language-specific translations. The labels XML parser also tolerates bare <labels> fragments that ship without the <?xml?> header or <CustomLabels> wrapper.

Excluding seed records from specific tests

By default every test receives the seeded records. Use nimbus.seed.record.exclude to opt specific test classes (or individual methods) out of seed injection. When a test matches, getAll() returns only test-inserted records — as if the org has no data for that custom setting type. Useful for selector tests that assert getAll() returns empty.

bash
# nimbus.properties
# Comma-separated ClassName or ClassName.method patterns
nimbus.seed.record.exclude=CountryCodeSettingSelectorTest,OtherTest.specificMethod

Full profile example

bash
# nimbus.properties

# Running user's profile (UserInfo.getProfileId() target)
nimbus.mock.user-profile=My Profile

# Additional profiles your tests query against
nimbus.seed.profiles=Field Sales,Partner Community

# Default record types for inserts without explicit RecordTypeId
nimbus.default-record-type.Lead=Applicant_Record_Type

# Seed list views not in repo metadata
nimbus.seed.list-view.Lead.AllLeads=All Leads

# Seed Site records for SOQL queries on Site/SiteDetail
nimbus.seed.site.My Portal=https://myportal.my.site.com

# Seed list custom setting org data
nimbus.seed.record.CountryCodeSetting__c.de=Land__c=Deutschland,Liefergebiete__c=Berlin

Custom Permissions

Custom permissions are boolean flags that code checks at runtime via FeatureManagement.checkPermission('My_Permission'). They are defined as .customPermission-meta.xml files and granted to users via permission sets (or profiles).

Nimbus loads all .customPermission-meta.xml files from the project automatically. It also parses the <customPermissions> blocks in every .permissionset-meta.xml file and wires up the underlying SetupEntityAccess records. All that remains is assigning the right permission sets to the running test user.

Assigning permission sets to the running user

Use nimbus.mock.permission-sets to specify which permission sets the running user holds. These must be API names matching your .permissionset-meta.xml filenames (without the extension).

bash
# nimbus.properties
nimbus.mock.permission-sets=Inventory_Manager,Support_Agent

With this set, FeatureManagement.checkPermission() returns true for any custom permission granted by those sets:

apex
// In production code:
if (FeatureManagement.checkPermission('Manage_Inventory')) {
    // This branch now executes in tests when Inventory_Manager PS is assigned
}

How it works end-to-end

Nimbus models the full Salesforce permission chain without hitting an org:

  1. .customPermission-meta.xmlCustomPermission record seeded in DB
  2. .permissionset-meta.xmlPermissionSet record + SetupEntityAccess linking PS → CustomPermission
  3. nimbus.mock.permission-setsPermissionSetAssignment linking running user → PermissionSet
  4. FeatureManagement.checkPermission(name) → queries this chain and returns true

Full permissions example

bash
# nimbus.properties

# Running user's profile
nimbus.mock.user-profile=My Profile

# Permission sets assigned to the running user
# API names match .permissionset-meta.xml filenames
nimbus.mock.permission-sets=Inventory_Manager,Support_Agent

# Additional profiles to seed for user creation in tests
nimbus.seed.profiles=Field Sales,Partner Community

Supported Metadata

Nimbus reads metadata directly from your SFDX project directory. No org sync required for most types — just point at your repo and run. This page lists every metadata type Nimbus understands today and what it does with each one.

Code

FlagDefaultDescription
.clsSupportedApex classes — parsed, compiled, and executed. Includes interfaces, enums, inner classes, and all annotations.
.triggerSupportedApex triggers — registered and fired automatically on DML operations.

Automation

FlagDefaultDescription
.flow-meta.xmlSupportedFlows — record-triggered, autolaunched, subflows, scheduled, and platform event flows are parsed and executed.
.validationRule-meta.xmlSupportedValidation rules — evaluated during DML operations.
Process BuilderPlannedProcess Builder (.process-meta.xml) is not yet supported. We recommend migrating to flows.
Workflow RulesPlannedWorkflow rules (.workflow-meta.xml) are not yet supported. We recommend migrating to flows.

Salesforce has been deprecating Process Builder and Workflow Rules in favor of Flow since 2022. We recommend converting them to flows using Salesforce's Migrate to Flow tool. Nimbus support for both is planned but not a priority.

Data & Schema

FlagDefaultDescription
Standard objectsSupportedCommon standard objects ship with embedded schemas (Account, Contact, Lead, Opportunity, Case, User, and more). No sync required.
.object-meta.xmlSupportedCustom objects — fields, record types, and relationships are used to build the local database schema.
.object-meta.xml (__mdt)SupportedCustom metadata types — object definitions discovered automatically from __mdt suffixed objects.
.object-meta.xml (__c settings)SupportedCustom settings (hierarchy and list) — object definitions loaded, records seedable via nimbus.properties.
.field-meta.xmlSupportedCustom fields — all standard field types including formula fields, lookups, and master-detail.
.fieldSet-meta.xmlSupportedField sets — parsed and available for FieldSet describe calls.
.recordType-meta.xmlSupportedRecord types — seeded into the database and available via SOQL.
.listView-meta.xmlSupportedList views — auto-discovered and seeded for ListView SOQL queries.
.globalValueSet-meta.xmlSupportedGlobal picklist value sets — loaded and referenced by picklist fields.
.standardValueSet-meta.xmlSupportedStandard picklist value sets (e.g. LeadSource, Industry).
.territory2-meta.xmlSupportedTerritory2 records — seeded and queryable via SOQL.

Security & Access

FlagDefaultDescription
.permissionset-meta.xmlSupportedPermission sets — parsed for custom permission grants and assignable to the running user.
.customPermission-meta.xmlSupportedCustom permissions — seeded and checkable via FeatureManagement.checkPermission().
.profile-meta.xmlPartialProfiles — standard profiles are pre-seeded. Custom profiles can be seeded via config. FLS/CRUD not enforced.

Configuration

FlagDefaultDescription
.labels-meta.xmlSupportedCustom labels — loaded and accessible via System.Label.
.translation-meta.xmlSupportedTranslations — label translations loaded per language.
.md-meta.xmlSupportedCustom metadata type records — seeded into __mdt tables and queryable via SOQL.
.resource-meta.xmlSupportedStatic resources — file content available for Test.loadStaticResource() and callout mocks.