Transform scripts let you handle complex data manipulation during imports that field mappings alone can't accomplish. You'll write JavaScript that runs during the transformation process to combine fields, look up related records, or conditionally skip rows entirely.
Why field mappings aren't enough
Basic transform maps work fine when you're doing simple one-to-one field mapping, but real data imports are messier. You need to concatenate first and last names, look up user records by employee ID, convert date formats, or skip rows that don't meet certain criteria. Without transform scripts, you're stuck preprocessing data in Excel or writing separate cleanup scripts that run after the import. Platform developers and integration specialists end up building fragile workarounds instead of handling the logic where it belongs — in the transform process itself.
How transform scripts execute
Transform scripts are JavaScript functions that run at specific points during the transformation process. onBefore scripts run before any field mappings execute — use these for data cleanup, validation, or setting variables you'll reference later. onAfter scripts run after all field mappings complete — use these for final calculations, related record updates, or logging. Field-level coalesce scripts run during individual field processing — use these sparingly for simple field-specific logic. Each script has access to the source staging record, target destination record, and the transform map itself through predefined objects.
Building robust transformation logic
Start with onBefore scripts for data validation and onAfter scripts for complex mapping logic. Add error handling that logs meaningful messages instead of failing silently. Use the ignore flag to skip invalid rows rather than creating bad data. Consider performance — transform scripts run for every imported row, so avoid expensive operations like complex GlideRecord queries inside loops. Well-built transform scripts handle edge cases gracefully, log enough detail for debugging, and fail fast when data quality issues require manual intervention.
Before you start
- •import_admin role or admin role
- •Existing transform map with source and target tables configured
Sourdough: ServiceNow Monitoring and Analytics
A Chrome extension for ServiceNow Admins and Developers with essential tools, analytics, graphs and monitoring features.
Free to install. Pro $5/month after a 14-day no-card trial.
Pro requires the ServiceNow admin role. Upgrade inside the extension.
Step by step
Open the transform map record
Navigate to System Import Sets > Administration > Transform Maps. Find your transform map and click to open it. You'll see the existing field mappings in the Field Maps related list at the bottom.
Use the search box to filter by transform map name — the list gets long in active instances.
Configure the script timing
Scroll to the Transform Scripts section. Choose 'Before field mappings are applied (onBefore)' for data cleanup and validation logic. Choose 'After field mappings are applied (onAfter)' for complex calculations that need the mapped data. The script will run once per imported row at the timing you select.
Write the transform script
In the Script field, write your JavaScript. Use 'source' to access the staging table record, 'target' to access the destination record, and 'map' to access the transform map. For example: target.u_full_name = source.u_first_name + ' ' + source.u_last_name; The script runs in the global scope with full GlideRecord access.
Add gs.log() statements for debugging — they'll appear in the system log with your transform map name.
Handle conditional row skipping
To skip rows conditionally, set ignore = true in your script. For example: if (source.u_status == 'inactive') { ignore = true; } Skipped rows won't create or update records in the target table, but they'll show as ignored in the import set results.
Add error handling
Wrap risky operations in try-catch blocks to prevent the entire import from failing. Log meaningful error messages that include the source record's sys_id for debugging. For example: try { var user = new GlideRecord('sys_user'); } catch (e) { gs.log('Transform error for ' + source.sys_id + ': ' + e.message); }
Use map.getTransformMapName() in your log messages to identify which transform map generated the error.
Test with sample data
Save the transform map and run a test import with a small data set. Check the import set results to verify your script logic worked correctly. Look for ignored rows, error messages in the system log, and whether target records contain the expected calculated values.
Optimize for performance
Review your script for expensive operations that run once per row. Move GlideRecord queries outside loops where possible. Cache lookup results in global variables if you're querying the same data repeatedly. Consider using GlideAggregate for counting operations instead of iterating through query results.
Best practices
Use onBefore scripts for data validation and onAfter scripts for complex mapping — don't put everything in onAfter just because it's the default.
Always include error handling with meaningful log messages that include the source record sys_id — silent failures in transform scripts are debugging nightmares.
Set ignore = true for invalid rows rather than creating bad data — it's easier to fix the source data and re-import than to clean up the target table later.
Cache lookup results in script-scoped variables when you're querying the same reference data for multiple rows — transform scripts run once per imported record.
Avoid field-level coalesce scripts unless you need them — they're harder to debug and maintain than centralized transform scripts.
Test Your Knowledge
Quick 3-question quiz — see how your ServiceNow skills stack up.
A list view on a table with millions of records is slow. Best fix?
Select an answer to continue