Field Creation and Mapping Configuration
Mapping files tell the migration tool how to translate fields between your source system and nevisID's SCIM schema. This page explains how to create user fields, the two mapping files, the SpEL expression syntax, and how to handle common mapping scenarios.
Pre-migration field setup in nevisIDM
Before running any migration, the target field structure must exist in nevisID - incoming SCIM data will only be stored if the corresponding properties are already defined. Some of this setup can be done through the nevisID administration GUI, specifically onProfileForApp and onRoleForApp properties can be created directly in the interface. However, general-purpose properties - including user global properties, profile global properties, and credential properties - cannot be created through the GUI and must be provisioned via the nevisIDM REST API before the migration is started. Please see examples for this among the references provided. It is therefore recommended to prepare an API script that creates all required custom properties in the correct scope, and to run and verify it against the target nevisID instance as part of the pre-migration setup, before any mapping files are configured or migration jobs are executed.

Mapping Overview
Mapping files tell the migration tool how to translate fields between your source system and NevisID's SCIM schema. Mappings are defined in YAML files using Spring Expression Language (SpEL) expressions:
inbound_mapping.yml— maps source fields to NevisID SCIM attributes (used in bulk and continuous inbound modes)outbound_mapping.yml— maps NevisID SCIM attributes back to legacy system fields (used in continuous outbound mode)scim_relay_mapping.yml— defines attribute renaming between the NevisID SCIM extension schema and a target SCIM schema (used in SCIM Relay Outbound mode)
A Mapping Generator utility mode is available to automatically produce a skeleton inbound_mapping.yml by introspecting the live NevisID SCIM schema, reducing the manual effort of discovering every field name and building the YAML structure by hand. Complete the pre-migration user field setup before running the mapping generator.
Overview of mapping files
| File | Used in modes | Direction |
|---|---|---|
inbound_mapping.yml | Bulk, Continuous Inbound | Source fields → SCIM attributes |
outbound_mapping.yml | Continuous Outbound (legacy backend) | SCIM attributes → foreign system fields |
scim_relay_mapping.yml | Continuous Outbound (SCIM backend) | nevisIDM SCIM schema → target SCIM schema |
Configure the paths to these files in application.yml:
migration:
mapping:
inbound-file: config/inbound_mapping.yml
outbound-file: config/outbound_mapping.yml
scim-relay-file: config/scim_relay_mapping.yml
SpEL expression variables
Mapping values are Spring Expression Language (SpEL) expressions enclosed in double quotes. The available root variables differ by mode:
| Variable | Available in | Contains |
|---|---|---|
#source | Inbound mapping | Map of the raw source record (one key per column/field) |
#scim | Outbound mapping | The SCIM User resource (core attributes) |
#ext | Outbound mapping | The nevisIDM extension (urn:nevis:idm:scim:schemas:v1:extension:User) |
#cred | Outbound mapping — credential block | A single credential object from the extension |
#prof | Outbound mapping — profile block | A single profile object from the extension |
Expressions are parsed once and cached by SpelExpressionCache, so there is no performance penalty for complex expressions in large migrations.
Inbound mapping example
nevisScim:
userName: "#source['loginId']"
name:
givenName: "#source['firstName']"
familyName: "#source['lastName']"
emails:
- value: "#source['email']"
primary: "true"
urn:nevis:idm:scim:schemas:v1:extension:User:
birthDate: "#source['dob']"
credentials:
- type: "'PASSWORD'"
password: "#source['passwordHash']"
state: "'ACTIVE'"
profiles:
- extId: "#source['profileId']"
name: "#source['profileName']"
Notice that literal string values require inner single quotes: "'PASSWORD'". Field references use bracket notation: "#source['fieldName']".
Outbound mapping example
foreign:
loginId: "#scim['userName']"
firstName: "#scim['name']['givenName']"
email: "#scim['emails'][0]['value']"
birthDate: "#ext['birthDate']"
credential:
type: "#cred['type']"
password: "#cred['type'] == 'PASSWORD' ? #cred['password'] : null"
context: "#cred['type'] == 'MTAN' ? #cred['context'] : null"
profile:
profileId: "#prof['extId']"
profileName: "#prof['name']"
Common mapping scenarios
Concatenating fields
displayName: "#source['firstName'] + ' ' + #source['lastName']"
Conditional value
active: "#source['status'] == 'A' ? 'true' : 'false'"
Default value when source field is null
locale: "#source['locale'] ?: 'de-CH'"
Custom transformation function
Register a custom function via MappingFunctions / FunctionRegistrar in the tool's extension point, then call it in your mapping:
phoneNumber: "#normalizePhone(#source['phone'])"
Supported credential types
The type field in the credentials block must be one of the 22 supported values:
PASSWORD, MTAN, GENERIC, CONTEXTPASSWORD, KERBEROS, SECURID, CERTIFICATE, OATH, FIDO_UAF, SAMLFEDERATION, RECOVERY_CODE, TICKET, SAFEWORDUSER, OTP, TEMPSTRONGPASSWORD, VASCO, PUK, URLTICKET, DEVICEPASSWORD, MOBILESIGNATURE, SECURITYQUESTIONS, FIDO2
Validating your mappings
After editing a mapping file, always validate using test-run mode before a live run:
./gradlew runBulk -PtestRun
The [TEST-RUN] log output shows the full SCIM payload that would be sent for each user, making it easy to confirm field values are correct.
Next steps
- To run a bulk import using your mapping, see Running Your First Migration.
- To set up ongoing sync, see Continuous Sync Setup.