Skip to content

How to Migrate from ServiceDesk Plus to ServiceNow: The Complete Guide

A technical guide to migrating from ServiceDesk Plus to ServiceNow. Covers API rate limits, CMDB relationship mapping, object transformations, and zero-downtime execution.

Roopi Roopi · · 29 min read
How to Migrate from ServiceDesk Plus to ServiceNow: The Complete Guide
TALK TO AN ENGINEER

Planning a migration?

Get a free 30-min call with our engineers. We'll review your setup and map out a custom migration plan — no obligation.

Schedule a free call
  • 1,500+ migrations completed
  • Zero downtime guaranteed
  • Transparent, fixed pricing
  • Project success responsibility
  • Post-migration support included

How to Migrate from ServiceDesk Plus to ServiceNow: The Complete Guide

Info

TLDR: Migrating from ServiceDesk Plus to ServiceNow is a relationship-heavy data migration that typically takes 3 to 10 weeks depending on record volume and CMDB complexity. The biggest risks are breaking CMDB parent-child relationships during load (ServiceNow enforces relationship depth limits that can silently truncate your CI graph) and hitting API rate limits during extraction. Native CSV exports from ServiceDesk Plus drop conversations, worklogs, and inline attachments, so API-based extraction is required for any production migration. Teams with fewer than 10,000 tickets and no CMDB data can handle this in-house. Organizations with complex CMDB topologies, multi-site configurations, or compliance requirements should use a managed migration service to avoid re-migration.

A ServiceDesk Plus to ServiceNow migration is the process of extracting ITSM data — incidents, problems, changes, assets, CMDB CIs, users, worklogs, and attachments — from ManageEngine ServiceDesk Plus and loading it into ServiceNow's data model while preserving ticket history, relationships, and operational continuity. This guide covers the real API constraints, object mapping, and execution sequence based on production migration experience.

For a side-by-side architecture comparison of these two platforms before you commit to migrating, see our ServiceNow vs ManageEngine ServiceDesk Plus: Architecture & TCO breakdown.

Why Enterprise IT Teams Move from ServiceDesk Plus to ServiceNow

The move is driven by scale, governance, or platform consolidation. ServiceDesk Plus works well for small to mid-size IT teams, but it hits specific architectural limits that ServiceNow does not.

  • Workflow engine depth. ServiceNow's Flow Designer supports multi-stage, cross-module orchestration with branching, parallel approvals, SLA timers, and subflows that can invoke Integration Hub spokes. ServiceDesk Plus request workflows support sequential approval stages and field-update actions but lack conditional branching, parallel execution, and cross-module orchestration within a single flow.
  • CMDB maturity. ServiceNow's Common Service Data Model (CSDM) provides a standards-based CI class hierarchy with over 400 out-of-box CI classes organized across five CSDM layers (Foundation, Product, Technical, Design, and Sell/Consume). ServiceDesk Plus uses a flat asset-centric model with user-defined CI types that becomes difficult to maintain past a few thousand CIs because relationships are not enforced by class type.
  • Enterprise integration surface. ServiceNow exposes IntegrationHub (with 600+ prebuilt spokes as of 2024), bidirectional REST/SOAP APIs, and event-driven integration via Flow Designer triggers. ServiceDesk Plus Cloud restricts API throughput with endpoint-specific rate limits (detailed below) that constrain real-time integration patterns and offers a smaller integration ecosystem.
  • Multi-instance consolidation. Large enterprises running ServiceDesk Plus across multiple sites often reach a point where consolidation into a single ServiceNow instance simplifies governance, reporting, and license management. ServiceNow's domain separation feature enables multi-tenant data isolation within a single instance, which ServiceDesk Plus does not offer.

The core data-model difference that makes this migration non-trivial: ServiceDesk Plus stores requests, assets, and CIs in loosely linked modules with numeric priority values and flat picklists. ServiceNow enforces a normalized relational model where every field reference resolves to a sys_id, every CI belongs to a typed class hierarchy, and relationships are stored in a dedicated cmdb_rel_ci table with typed relationship descriptors like Runs on::Runs and Hosted on::Hosts.

ServiceDesk Plus to ServiceNow Object Mapping

The mapping table below covers the core ITSM objects. Every row represents a real mapping decision your migration script must handle.

ServiceDesk Plus Object ServiceNow Object Notes / Caveats
Requests (Incident type) Incident (incident) SDP uses a single "Request" object with a type field. Filter on is_service_request = false. Map resolution codes carefully; state transitions must align with ServiceNow's ITIL state model (New=1, In Progress=2, On Hold=3, Resolved=6, Closed=7).
Requests (Service Request type) Requested Item (sc_req_item) Service Requests map to RITMs, not directly to incident. Catalog items and variable sets must exist in ServiceNow first. Each RITM requires a parent Request (sc_request) record.
Problems Problem (problem) Direct mapping. Problem tasks in ServiceNow are child records (problem_task) that SDP does not separate natively — SDP embeds task tracking within the problem record itself.
Changes Change Request (change_request) Map SDP change types (Standard, Normal, Emergency) to ServiceNow's Type field. Rebuild approvals and workflows separately from data load — ServiceNow change approvals live in sysapproval_approver, not on the change record itself.
Assets Asset (alm_asset) SDP asset types map to ServiceNow CI classes via asset-CI pairing. Do not force every asset into CMDB if it is really ownership or lifecycle data — ServiceNow distinguishes between alm_asset (financial/lifecycle) and cmdb_ci (technical/operational).
CIs (CMDB) CMDB CI (cmdb_ci_*) SDP uses flat CI types. ServiceNow requires mapping to specific class tables (e.g., cmdb_ci_server, cmdb_ci_app_server, cmdb_ci_win_server). Load CIs first; load relationships only after target sys_ids exist.
Requesters User (sys_user) SDP separates requesters and technicians into distinct tables. ServiceNow uses a single sys_user table with role assignments. Map email addresses as the primary coalesce value.
Technicians User (sys_user) Merge with requesters. Assign itil role for agent access. If a person exists in both SDP tables, deduplicate by email before loading.
Support Groups Group (sys_user_group) Ensure group membership records (sys_user_grmember) are loaded before ticket assignment references.
Solutions Knowledge Article (kb_knowledge) SDP Solutions map to ServiceNow Knowledge Base articles. HTML cleanup is usually required — SDP stores solutions with ManageEngine-specific HTML formatting. Requires a target knowledge base and category structure to exist first.
Request Notes Comments / Work Notes (sys_journal_field) Use the SDP show_to_requester flag to determine whether a note maps to ServiceNow's customer-visible comments or internal work notes. (manageengine.com)
Worklogs Time Card (time_card) or Journal Entry Use Time Cards only if your ServiceNow instance has Time Card Management enabled. Otherwise, map to journal entries on the parent record. Timestamps must be preserved in UTC.
Attachments Attachment (sys_attachment) Binary files linked via table_sys_id. ServiceNow's default maximum attachment size is 24 MB per file (configurable via com.glide.attachment.max_size property). Must be downloaded from the SDP API and uploaded via the ServiceNow Attachment API.
Notifications No direct equivalent SDP notification history does not migrate. ServiceNow generates its own notification logs via sys_email.

Field-Level Data Type Transformations

ServiceDesk Plus stores priority as numeric values (typically 1 through 4, where 1 = High in default configuration). ServiceNow priority is also numeric (1–4) but resolves through an Impact × Urgency matrix lookup. Each combination maps to a priority value via the dl_u_priority table or data lookup rules. Your transform script must map SDP priority integers to the correct ServiceNow Impact/Urgency combination — not just copy the number — because a direct numeric copy will produce incorrect priority calculations when ServiceNow re-evaluates.

SDP request notes carry an HTML description plus visibility flags like show_to_requester, while ServiceNow incident records expose separate journal fields: comments (customer-visible, field name comments) and work_notes (internal, field name work_notes). SDP requests also use nested JSON objects for requester, technician, group, status, and priority. ServiceNow resolves many of those values through reference fields (storing sys_id pointers) and choice lists (sys_choice records). (manageengine.com)

SDP custom fields use simple types: single-line text, multi-line text, dropdown, checkbox, date, and numeric. ServiceNow custom fields live on dictionary entries (sys_dictionary) with explicit max lengths, reference qualifiers, and choice list dependencies. Every SDP dropdown value must be pre-loaded into ServiceNow's sys_choice table before ticket import, or the field will silently default to empty — ServiceNow does not create choice values on the fly during import.

Two practical rules help avoid mapping failures:

  1. Map by meaning, not by label or numeric value. Priority is a good example — copying a raw source number rarely produces the right operational behavior in ServiceNow. Document the explicit mapping (e.g., SDP Priority 1 "High" → ServiceNow Impact 2 + Urgency 1 → Priority 2) and get stakeholder sign-off.
  2. Preserve source identifiers. Keep the original SDP request ID, display ID, status name, and technician name in searchable custom fields (e.g., u_legacy_sdp_id, u_legacy_sdp_status). Agents need these during hypercare for search and reconciliation.
Warning

If you migrate every historical ServiceDesk Plus service request into Incident because it is easier, reporting gets simpler but catalog fidelity is gone. If you rebuild them as Request plus Requested Item, you preserve service request structure but increase mapping, validation, and test effort by roughly 40% because you must create catalog items, variable sets, and RITM-to-Request parent relationships. Make this decision explicitly during discovery and document its reporting impact.

What Has No Clean Equivalent in ServiceNow

  • SDP Request "Mode" field (Phone Call, Email, Web Form) has no default equivalent in the Incident table. Map to ServiceNow's contact_type field (which supports values like phone, email, self-service, walk-in) or create a custom field.
  • SDP "Due by time" vs. ServiceNow SLA-driven due dates. SDP stores a static due date on the request. ServiceNow calculates due dates dynamically from SLA definitions attached to the task_sla table. You can write the historical due date to a custom field (e.g., u_legacy_due_date), but active SLA tracking will not honor it — ServiceNow will calculate its own due dates based on SLA definitions applied to the record.
  • SDP Purchase Orders and Contracts. ServiceNow has procurement modules (Procurement > Purchase Orders, Contract Management), but they use a different schema (proc_po, ast_contract). These objects require a separate mapping effort outside the ITSM migration scope.
  • SDP ticket numbers. ServiceNow auto-generates ticket numbers (e.g., INC0010001) using a number sequence (sys_number) and does not allow direct control over the Number field via API import or Import Sets. Store the original SDP ticket ID in a custom field (e.g., u_legacy_sdp_id) for cross-reference. Index this field for query performance.

Migration Architecture: Extracting Data and Managing API Limits

ServiceDesk Plus Cloud Extraction

ServiceDesk Plus Cloud exposes a REST API (v3) with per-operation rate limits that directly constrain extraction throughput. Based on ManageEngine's published rate limit documentation (pitstop.manageengine.com):

Operation Throttle Limit Duration Lock Period if Exceeded
Request creation 15 calls 10 seconds 5 minutes
Request update 30 calls 1 minute 5 minutes
Request deletion 30 calls 1 minute 5 minutes
Request GET (single and list) 60 calls 1 minute 5 minutes
Request close 30 calls 1 minute 5 minutes

The 5-minute lock period is the real constraint. If your extraction script exceeds the limit on any operation, the API locks that endpoint for 5 full minutes — not just the current request. There is no Retry-After header; you must implement your own 310-second wait.

Pagination uses start_index and row_count inside the input_data JSON parameter. The maximum row_count is 100 per page. The default is 10, so always set this explicitly or you will make 10x more API calls than necessary. (manageengine.com)

Authentication differs between deployment models:

  • ServiceDesk Plus Cloud uses OAuth 2.0 via Zoho Accounts (accounts.zoho.com). The token scope needed is SDPOnDemand.requests.ALL for request data and SDPOnDemand.assets.ALL for asset and CI data. Tokens expire after 1 hour; implement automatic refresh using the refresh token. (manageengine.com)
  • ServiceDesk Plus On-Premises uses a TECHNICIAN_KEY header for API authentication. This is a static key generated per technician in Admin > Technicians > API Key Generation. On-Premises installations also offer direct database access (PostgreSQL or MSSQL depending on configuration), which bypasses API rate limits entirely. If your On-Prem instance uses MSSQL, you can extract data directly via SQL queries against the WorkOrder, WorkOrderStates, SDUser, Resources, and CI tables — this is significantly faster than API extraction for large datasets.

Example extraction call with pagination and rate limit handling:

import requests
import json
import time
 
BASE_URL = "https://sdpondemand.manageengine.com/app/portal/api/v3"
HEADERS = {
    "Authorization": "Zoho-oauthtoken YOUR_TOKEN",
    "Accept": "application/vnd.manageengine.sdp.v3+json"
}
 
def extract_requests(start=1, page_size=100):
    all_requests = []
    has_more = True
    index = start
 
    while has_more:
        list_info = {"list_info": {"row_count": page_size, "start_index": index}}
        params = {"input_data": json.dumps(list_info)}
 
        response = requests.get(f"{BASE_URL}/requests", headers=HEADERS, params=params)
 
        if response.status_code == 429:
            # API locked for 5 minutes on rate limit breach
            print("Rate limit hit. Waiting 310 seconds.")
            time.sleep(310)
            continue
 
        if response.status_code == 401:
            # Token expired — refresh and retry
            refresh_oauth_token()
            continue
 
        data = response.json()
        all_requests.extend(data.get("requests", []))
        has_more = data.get("list_info", {}).get("has_more_rows", False)
        index += page_size
 
        # Stay under 60 GET calls per minute
        time.sleep(1.1)
 
    return all_requests

ServiceDesk Plus On-Premises: Direct Database Extraction

For On-Premises installations with large datasets (over 50,000 tickets), direct database extraction bypasses API rate limits entirely. ServiceDesk Plus On-Prem uses PostgreSQL (default) or MSSQL as its backend database.

Key tables for direct extraction:

SDP Database Table Contains
WorkOrder All requests (incidents and service requests)
WorkOrderStates Status history per request
SDUser Requesters
AaaUser / Technician Technicians
Resources Assets
CI CMDB configuration items
CIRelationship CI-to-CI relationships
WorkOrderNotes Request notes and conversations
WorkLog Time tracking entries

Direct database extraction requires coordination with the SDP database administrator and carries the risk of reading data in an inconsistent state if the application is actively writing. Take a database snapshot before extraction. This approach is not available for Cloud deployments.

ServiceNow Load: Import Sets and API Limits

ServiceNow's recommended bulk ingestion path is the Import Set API. You create a staging table (prefix u_), push data into it via the /api/now/import/{staging_table} endpoint, then run a Transform Map to coerce and insert records into the target table.

The insertMultiple endpoint accepts batches. ServiceNow's documentation recommends starting at 200 records per batch and scaling up while monitoring instance performance via the sys_node_stats table or Performance Analytics. The Import Set POST endpoints accept only string name-value pairs, so nested JSON from ServiceDesk Plus must be flattened before staging. For CI loads, ServiceNow explicitly recommends Import Set ... insertMultiple over the older CMDB Data Ingestion API for better scalability and stability. (servicenow.com)

Transform Map Configuration

Each staging table needs a Transform Map that defines:

  • Field mappings — source column to target field
  • Coalesce fields — the field(s) used to determine insert vs. update (e.g., coalesce on u_legacy_sdp_id to prevent duplicates on re-runs)
  • Choice action — set to "reject" to catch unmapped choice values rather than silently inserting blanks
  • Transform scripts — onBefore, onAfter, and field-level scripts for data transformation

Example Transform Map script for priority conversion:

// onBefore transform script — map SDP priority to ServiceNow Impact/Urgency
(function runTransformScript(source, map, log, target) {
    var sdpPriority = source.u_sdp_priority;
    // SDP: 1=High, 2=Medium, 3=Normal, 4=Low
    // ServiceNow: Impact (1=High,2=Medium,3=Low) x Urgency (1=High,2=Medium,3=Low)
    var priorityMap = {
        '1': {impact: '1', urgency: '1'},  // High → Impact High, Urgency High
        '2': {impact: '2', urgency: '2'},  // Medium → Impact Medium, Urgency Medium
        '3': {impact: '2', urgency: '3'},  // Normal → Impact Medium, Urgency Low
        '4': {impact: '3', urgency: '3'}   // Low → Impact Low, Urgency Low
    };
    var mapped = priorityMap[sdpPriority] || {impact: '3', urgency: '3'};
    target.impact = mapped.impact;
    target.urgency = mapped.urgency;
})(source, map, log, target);

ServiceNow's throughput is governed by semaphores, not a simple RPM cap. Each application node has a pool of semaphores (the default is 16 per node). When all active semaphores are busy, incoming requests queue (default queue depth of 150 for web transactions, with a separate API integration queue of 50 governed by glide.rest.throttle.max_queue). When the queue is full, ServiceNow returns HTTP 429. You may also see HTTP 202 for queued requests. Instances can have explicit inbound REST rate limit rules per hour, configured via System Web Services > Inbound > REST Rate Limits, with X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After headers. (servicenow.com)

MID Server consideration: If your ServiceNow instance uses a MID Server for integrations (common in enterprise deployments with network restrictions), route your import API calls through the MID Server to avoid firewall issues. Configure the MID Server's mid.property.max_threads to control concurrent import throughput.

The practical implication: do not run migration loads during business hours on a production instance. Schedule data loads for maintenance windows or use a sub-production instance and promote the data via XML export/import or Update Sets (for configuration) combined with data migration scripts.

For more on ServiceNow-side ingestion challenges, see 10 ServiceNow Data Migration Challenges & How to Overcome Them.

Throughput Math

Header extraction can look fast on paper, but child extraction dominates elapsed time. With row_count = 100 and 60 GET calls per minute, the theoretical ceiling for request headers is 6,000 rows per minute. That number is misleading for real migrations. If 100,000 tickets each require notes, worklogs, and attachment metadata in three extra GET calls per ticket, that is 300,000 child calls — roughly 5,000 minutes (~83 hours) of child extraction at the documented 60 GET calls per minute, before retries or lockout penalties.

For a migration of 200,000 incidents with worklogs and attachments:

  • Extraction from SDP Cloud: ~24 to 48 hours (rate-limited by the 60 GET calls/minute ceiling and 5-minute lockout risk). SDP On-Prem with direct database extraction: 1 to 4 hours.
  • Transform and staging: 2 to 4 hours (local processing — JSON flattening, deduplication, timestamp conversion)
  • Load into ServiceNow: 4 to 8 hours at 200 records per batch with moderate business rule complexity. Disable non-essential business rules on target tables during load to improve throughput by 30–50%.
  • Attachment upload: Highly variable. A 5 MB average file size across 200,000 attachments represents ~1 TB of binary data. Plan 8 to 16 hours for attachment transfer alone. ServiceNow's Attachment API accepts multipart/form-data; base64 encoding inflates payload size by ~33%.

Your retry logic should assume throttling, not treat it as an exception path:

retryable = {202, 429}
 
while True:
    response = send_batch()
    if response.status_code in retryable:
        retry_after = int(response.headers.get('Retry-After', 5))
        time.sleep(retry_after)
        continue
    if response.status_code >= 400:
        log_error(response)
        break
    break

Honor Retry-After, cap concurrency, and log every source ID to target sys_id mapping to a reconciliation table.

Common Error Codes and Handling

Source HTTP Code Meaning Action
SDP Cloud 429 Rate limit exceeded Wait 310 seconds (5-minute lockout + buffer)
SDP Cloud 401 OAuth token expired Refresh token and retry
SDP Cloud 400 Malformed input_data parameter Log payload and fix JSON structure
ServiceNow 429 Semaphore queue full Honor Retry-After header; reduce batch concurrency
ServiceNow 202 Request queued but not yet processed Poll for completion; do not resubmit
ServiceNow 403 ACL denied — user lacks table access Verify import user has import_set_loader and import_transformer roles
ServiceNow Transform Error record in import set Coalesce failed or reference not found Check sys_import_state_comment on the import set row for the specific error message. Common causes: target reference field has no matching sys_id, choice value not in sys_choice, mandatory field is null

What Data Cannot Be Migrated Natively from ServiceDesk Plus?

ServiceDesk Plus Cloud offers a built-in data export under Setup > Data Administration > Export Data. It supports CSV and XLSX formats for Users, Requests, Problems, Changes, Releases, Purchase Orders, Solutions, Attachments, Categories, Contracts, Vendors, Assets, and Conversations. (manageengine.com)

This native export has hard limitations:

  • Files larger than 500 MB are automatically split into multiple zip files. Reassembling them requires custom scripting, and the split boundaries can break mid-record in CSV format — a partial row at the end of one file and the continuation at the start of the next.
  • Worklogs and time entries are not included in the standard request export. They require separate API extraction via /api/v3/requests/{id}/worklogs.
  • Inline attachments embedded in conversation HTML are not exported as discrete files. They are embedded as base64 or linked to SDP-hosted URLs that will break after decommissioning. You must parse conversation HTML, extract embedded images, download them separately, and re-link them in ServiceNow.
  • CMDB relationship data (parent-child, HostedOn, RunsOn) is not preserved in the flat CSV export. You get a flat list of CIs with no relationship context.
  • Conversation threading and chronological ordering must be reconstructed from timestamps. The CSV export does not guarantee sort order.
  • Custom field values may export as internal IDs rather than display values for dropdown fields, requiring a separate lookup table export to resolve.

ManageEngine's own admin documentation tells customers to contact support for full data export — the platform itself acknowledges that full-fidelity extraction is a separate exercise from a normal UI export.

For any migration involving more than basic ticket data, the API-based extraction path is the only viable option.

Can ServiceDesk Plus CMDB History Be Preserved in ServiceNow?

Yes, but with significant constraints. ServiceDesk Plus CMDB data can be extracted via the /api/v3/cmdb endpoints and loaded into ServiceNow's cmdb_ci_* class tables. The challenge is relationships. (manageengine.com)

ServiceNow CMDB stores all CI relationships in the cmdb_rel_ci table using typed relationship descriptors. Each relationship record links a parent CI (parent) to a child CI (child) with a type reference (type) pointing to cmdb_rel_type. Common types include Runs on::Runs, Hosted on::Hosts, Depends on::Used by, and Contains::Contained by. The cmdb_rel_type table contains approximately 30 out-of-box relationship types.

ServiceDesk Plus relationships are simpler and often untyped — they store a generic "related to" association without distinguishing between dependency, containment, and hosting relationships. Your migration must:

  1. Extract SDP CI relationships via the API (not available in CSV export). The endpoint is /api/v3/cmdb/ci/{ci_id}/relationships.
  2. Map SDP relationship types to ServiceNow relationship type sys_ids from the cmdb_rel_type table. If SDP relationships are untyped, you must infer the type from CI classes (e.g., a relationship between a cmdb_ci_app_server and cmdb_ci_server is likely Runs on::Runs).
  3. Load CIs before relationships to ensure both parent and child sys_ids exist. Attempting to create a cmdb_rel_ci record with a nonexistent parent or child sys_id produces an error record in the import set.
  4. Monitor relationship depth to avoid ServiceNow's "Maximum relationship limit has been reached" error.

ServiceNow's relationship level setting (controlled by the ecmdb.levels user preference, default value of 3) determines how many layers of relationships are loaded and displayed in the dependency view. At levels 4 and 5, the system can produce incomplete data and significant slowdowns during impact analysis because the number of related CIs grows exponentially. Errors like "Maximum relationship limit has been reached" or "Maximum number of queries has been reached" are common at these depths.

For most production environments, keeping imported relationships at 2 to 3 levels deep provides the best balance of visibility and performance. If your SDP CMDB has deeply nested relationships (e.g., Application → Web Server → VM → Host → Cluster → Data Center — 6 levels), plan to flatten or restructure the hierarchy during transformation. Common strategies: collapse the VM→Host→Cluster chain into a direct Hosted on relationship from Application to Host, and capture the intermediate layers as attributes rather than separate CIs.

CMDB Health validation after load: Run ServiceNow's CMDB Health Dashboard (navigate to Configuration > CMDB Dashboard) to check for:

  • Orphan CIs (CIs with no relationships — may be intentional but should be reviewed)
  • Duplicate CIs (same serial number or name in the same class)
  • Stale CIs (imported CIs with no discovery source that will never be updated)
  • Orphan relationships (relationship records pointing to deleted or nonexistent CIs)
Danger

Do not validate a CMDB migration by opening one giant dependency view and hoping it renders. Validate by CI class, relationship type, and sampled parent-child pairs. Use GlideRecord queries to systematically check relationship integrity:

// Find orphan relationships — cmdb_rel_ci records where parent or child CI doesn't exist
var gr = new GlideRecord('cmdb_rel_ci');
gr.addQuery('parent', '');
gr.addOrCondition('child', '');
gr.query();
gs.info('Orphan relationships found: ' + gr.getRowCount());

This catches broken keys earlier and avoids the platform rendering limits the system warns about.

Domain Separation Considerations

For enterprise ServiceNow instances with domain separation enabled, the migration load path changes materially:

  • Every imported record must include a sys_domain value, or it will land in the global domain.
  • Transform Maps must set the domain based on source site/location mapping.
  • Users must have domain-appropriate roles, or they will not see migrated records.
  • CMDB CIs can span domains, but relationships between CIs in different domains require careful ACL configuration.
  • Import Set staging tables are not domain-separated by default — you must configure domain separation on custom staging tables if you need domain-aware transforms.

If your ServiceNow instance uses domain separation and your SDP deployment spans multiple sites, map each SDP site to a ServiceNow domain during the discovery phase.

Migration Approaches: DIY vs. Native vs. Managed Service

Approach How It Works Best For Risk Complexity
Native CSV Export/Import Export from SDP Data Administration, import via ServiceNow Import Sets Small instances (<5,000 tickets), no CMDB High — loses relationships, worklogs, attachments Low
Custom API Scripts (Python/Node.js) Write extraction scripts against SDP v3 API, transform locally, push to ServiceNow Import Set API Mid-size (5K to 100K tickets) with dedicated dev resources who know both platforms Medium — requires retry logic, rate limit handling, relationship ordering High
Third-Party Migration Tool Automated tool with pre-built SDP connector Simple ticket migrations without deep CMDB Medium — limited field mapping customization, may not handle CMDB relationships or conversation threading Low
Integration Platform (e.g., ZigiOps) No-code bidirectional sync for ongoing integration Ongoing sync or coexistence, not one-time historical migration Low for sync, but not designed for historical bulk migration or data remodeling Medium
Managed Migration Service Dedicated engineers handle extraction, transformation, loading, and validation Enterprise (100K+ records), complex CMDB, compliance requirements Low — handled by specialists with rollback capability Low (for the customer)

The distinction between a one-time historical re-platform and ongoing e-bonding between two live ITSM tools matters. Tools positioned around automated help desk replication solve a different problem than integration platforms designed for bidirectional sync.

Clear picks:

  • Small team, under 5,000 tickets, no CMDB: Native CSV export to ServiceNow Import Sets can work. Budget 1 to 2 weeks for manual cleanup.
  • Mid-size, 5,000 to 100,000 tickets with CMDB: Custom API scripts if you have an engineer who knows both platforms. Budget 4 to 6 weeks.
  • Enterprise, 100K+ records, multi-site, compliance: Managed migration service. The engineering cost of building, debugging, and validating custom scripts typically exceeds the cost of hiring specialists — particularly when you factor in re-migration risk.
  • Parallel run or long coexistence: Integration platform for ongoing sync, but plan a separate effort for historical data remodeling.

ServiceNow Licensing Impact

ServiceNow licensing affects what you can import and where:

  • ITSM Standard does not include Performance Analytics, Agent Workspace, or Virtual Agent. If your migration plan assumes these features for validation or post-migration operations, verify your license tier.
  • Custom tables (prefix u_) for staging or legacy data may consume table quota depending on your contract. Check with your ServiceNow account team before creating staging tables you plan to keep post-migration.
  • CMDB CI count may be subject to licensing thresholds. ServiceNow's ITSM Pro and Enterprise tiers include CMDB, but the number of CIs under active management (with Discovery or Service Mapping) may have contractual limits.
  • Integration Hub spokes and actions beyond the included quota may incur additional licensing costs if you plan to use Flow Designer for ongoing SDP-to-ServiceNow sync during a parallel run.

If a DIY script fails mid-migration and you need to recover, see Help Desk Data Migration Failed? The Engineer's Rescue Guide.

Step-by-Step Process for a Zero-Downtime Migration

The order of operations determines whether relationships survive or break. Loading tickets before users exist means every requester and assignee field will be empty or default. Loading CMDB relationships before CIs exist means orphaned relationship records.

For a complete treatment of zero-downtime migration strategy, see Zero-Downtime Help Desk Data Migration.

Phase 1: Discovery and Audit (Week 1)

  • Inventory all SDP modules in use: Requests, Problems, Changes, Assets, CMDB, Solutions, Purchase Orders
  • Count records per module and per status (use SDP's Reports module or API list endpoints with row_count=1 to get total counts from list_info.total_count)
  • Document all custom fields, custom statuses, and custom templates
  • Identify SDP integrations (email parsing rules, Active Directory sync, third-party connectors) that will need ServiceNow equivalents
  • Export a sample of 100 records per module for mapping validation
  • Decide what becomes live operational data versus historical archive (common split: last 12–24 months as active, older records as read-only archive)
  • Audit compliance requirements: If SOX, HIPAA, or ITIL audit trails apply, document the chain-of-custody requirements for migrated data — what hash verification is needed, what migration logs must be retained, and what sign-off process is required before decommissioning SDP

Phase 2: Build the Mapping and Transform Rules (Week 2)

  • Create the object mapping table (use the one above as a starting point)
  • Map every SDP custom field to a ServiceNow dictionary entry — create u_ prefixed fields in ServiceNow before loading
  • Pre-load all choice list values into ServiceNow's sys_choice table
  • Build Transform Maps in ServiceNow for each staging table
  • Write and test coalesce rules — the logic that determines insert vs. update on each record. Recommended coalesce fields: u_legacy_sdp_id for tickets, email for users, serial_number or name for CIs
  • Test transforms with the 100-record sample from Phase 1

Phase 3: Extract from ServiceDesk Plus (Week 2 to 3)

Extraction sequence matters. Pull reference data before transactional data:

  1. Users (Requesters and Technicians) via /api/v3/requesters and /api/v3/technicians
  2. Groups (Support Groups) via /api/v3/support_groups
  3. Categories and Subcategories via /api/v3/categories
  4. Solutions (Knowledge Articles) via /api/v3/solutions
  5. Assets and CIs via /api/v3/assets and /api/v3/cmdb
  6. Requests (Incidents and Service Requests) via /api/v3/requests with pagination
  7. Worklogs per request via /api/v3/requests/{id}/worklogs
  8. Conversations per request via /api/v3/requests/{id}/conversations
  9. Attachments per request via /api/v3/requests/{id}/attachments (download binary)
  10. Problems via /api/v3/problems
  11. Changes via /api/v3/changes
  12. CMDB Relationships via /api/v3/cmdb/ci/{ci_id}/relationships (extract after all CIs are extracted)

Example extraction call using curl:

curl -G '<service-domain>/app/<portal>/api/v3/requests' \
  -H 'Accept: application/vnd.manageengine.sdp.v3+json' \
  -H 'Authorization: Zoho-oauthtoken <token>' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'input_data={"list_info":{"row_count":100,"start_index":1,"sort_field":"created_time","sort_order":"desc"}}'

Phase 4: Transform and Clean (Week 3)

  • Deduplicate users by email address (SDP allows the same person as both requester and technician with different internal IDs)
  • Normalize status values to ServiceNow's fixed lifecycle (New=1, In Progress=2, On Hold=3, Resolved=6, Closed=7, Canceled=8)
  • Convert SDP priority integers to ServiceNow Impact/Urgency pairs using the documented mapping
  • Strip SDP-internal HTML from conversation bodies (ManageEngine adds platform-specific CSS classes and inline styles)
  • Resolve SDP user IDs to email addresses for ServiceNow user coalescing
  • Convert all timestamps to UTC (SDP stores timestamps in the instance's configured timezone; ServiceNow stores UTC internally and renders in the user's timezone)
  • Generate SHA-256 hashes of extracted data files for audit trail if compliance requires chain-of-custody verification

Phase 5: Load into ServiceNow (Week 3 to 4)

Load order prevents broken references:

  1. Users and Groups
  2. Categories and Knowledge Base structure
  3. Knowledge Articles
  4. CMDB CIs (load by class, starting with base infrastructure classes: cmdb_ci_servercmdb_ci_app_servercmdb_ci_service)
  5. CMDB Relationships (via cmdb_rel_ci import set)
  6. Incidents (with requester, assignee, and group references resolved via coalesce)
  7. Worklogs and Conversations (as journal entries on parent records)
  8. Attachments (binary upload linked via table_sys_id)
  9. Service Requests → Requests (sc_request) → Requested Items (sc_req_item)
  10. Problems and Changes
  11. Cross-record links (incident-to-problem via problem_id field, incident-to-change associations)

Before loading any data, apply these ServiceNow instance settings:

// Disable SLA processing for historical records
// Set the property before load, revert after
gs.setProperty('com.snc.sla.engine.enabled', 'false');
 
// Or more selectively, set on each imported record:
// target.sla_due = '';  // Clear SLA due date to prevent recalculation

Use sysparm_suppress_auto_sys_field=true on Import Set API calls to prevent ServiceNow from overwriting sys_created_on and sys_created_by with current values — this preserves historical timestamps.

Example ServiceNow Import Set load:

curl 'https://<instance>.service-now.com/api/now/import/u_sdp_request_stage/insertMultiple' \
  --request POST \
  --header 'Accept:application/json' \
  --header 'Content-Type:application/json' \
  --header 'Authorization:Basic <base64_credentials>' \
  --data '{"records":[{"u_sdp_id":"2079997951635005","u_subject":"Need an External Monitor","u_created_on":"2024-01-15 14:30:00"}]}'

Phase 6: Validate and Reconcile (Week 4 to 5)

  • Record count reconciliation per object type
  • Spot-check 5% sample of tickets for field accuracy
  • Verify all CMDB relationships resolve (no orphaned cmdb_rel_ci records)
  • Confirm attachment accessibility
  • Run ServiceNow CMDB Health Dashboard to check for orphan relationships and stale CIs
  • Validate worklog chronological ordering and correct public/private visibility

Validation queries for reconciliation:

// Count incidents by source verification
var gr = new GlideRecord('incident');
gr.addNotNullQuery('u_legacy_sdp_id');
gr.query();
gs.info('Migrated incidents: ' + gr.getRowCount());
 
// Find incidents with unresolved requester references
var gr2 = new GlideRecord('incident');
gr2.addNotNullQuery('u_legacy_sdp_id');
gr2.addNullQuery('caller_id');
gr2.query();
gs.info('Incidents with null caller: ' + gr2.getRowCount());
 
// Verify attachment counts match
var gr3 = new GlideRecord('sys_attachment');
gr3.addQuery('table_name', 'incident');
gr3.query();
gs.info('Incident attachments: ' + gr3.getRowCount());

Phase 7: Delta Sync and Cutover

  • Run a final API pass to capture any tickets created or updated in ServiceDesk Plus during the migration window. Use created_time and last_updated_time filters in the SDP API to pull only delta records.
  • Execute cutover during a planned maintenance window (typically a weekend)
  • Redirect agents to ServiceNow
  • Keep ServiceDesk Plus in read-only mode for at least 30 days post-cutover as your rollback path
Warning

If you load historical tickets into ServiceNow without suppressing notifications and SLA rules, every resolved ticket from the past several years can trigger an email to the original requester. Use sysparm_suppress_auto_sys_field=true on Import Set loads and disable SLA processing for historical records before loading. This is the single most common post-migration incident. In one observed case, a migration of 150,000 historical incidents without notification suppression generated over 80,000 outbound emails in 45 minutes before the email queue could be manually paused.

Rollback Procedure

Build a rollback plan before go-live. ServiceNow's Update Sets cover configuration, not data. Your rollback must be a data-level revert:

  1. Before import: Export each target table's current state using ServiceNow's XML export (/sys_export.do?sysparm_query=...&XML). For large tables, use background scripts with GlideRecord to export in batches.
  2. Rollback execution: If validation fails, delete all records with u_legacy_sdp_id IS NOT NULL from each target table, then re-import the pre-migration XML exports.
  3. CMDB rollback: Delete relationships first (cmdb_rel_ci records), then CIs. Reversing this order leaves orphan relationship records.
  4. Timeline: A data-level rollback for 200K+ records across 8–10 tables takes 2 to 6 hours depending on business rule complexity. Test the rollback procedure in sub-production before go-live.

Go-live criteria should be concrete: agents can search by old SDP ID, record counts reconcile per object type within 0.1%, public versus internal notes are correctly mapped, attachments open, sampled CIs show the right parent-child relationships, and historical loads have not triggered notifications or automations.

How Long Does a ServiceDesk Plus to ServiceNow Migration Take?

A realistic timeline depends on record volume, CMDB complexity, and the number of custom fields.

Scenario Record Volume CMDB Complexity Timeline
Small IT team Under 10,000 tickets, no CMDB None 2 to 3 weeks
Mid-size organization 10,000 to 100,000 tickets, basic CMDB 500 to 5,000 CIs, 2 levels deep 4 to 6 weeks
Enterprise 100,000+ tickets, full CMDB 5,000+ CIs, 3+ levels, multi-site 6 to 10 weeks
Enterprise with domain separation 100,000+ tickets, full CMDB, multi-domain ServiceNow 5,000+ CIs, 3+ levels, multi-site, multi-domain 8 to 14 weeks

The extraction phase alone accounts for 30 to 40% of the total calendar time due to API rate limits (Cloud) or database coordination (On-Prem). The validation phase accounts for another 20 to 25%. Teams that underestimate validation end up discovering data quality issues in production.

Most delays come from mapping decisions and validation, not from the first successful API call. Common sources of delay:

  • Stakeholder disagreement on service request handling (Incident vs. RITM) — 1 to 2 weeks
  • SDP custom field mapping to ServiceNow dictionary entries — 3 to 5 days
  • CMDB class mapping decisions — 2 to 4 days
  • Re-run after discovering data quality issues in validation — 1 to 2 weeks

Edge Cases and Known Limitations

  • Duplicate users across SDP Requester and Technician tables. A single person can have both a requester record and a technician record in ServiceDesk Plus with different internal IDs. ServiceNow uses one sys_user record per person. Deduplicate by email before loading. If the same email has different names in requester vs. technician records, choose the technician record as the canonical source.
  • SDP custom statuses vs. ServiceNow fixed statuses. ServiceDesk Plus allows custom statuses (e.g., "Waiting for Vendor", "Pending Approval"). ServiceNow Incident uses a fixed status lifecycle (1–8). Custom statuses must be mapped to ServiceNow's standard values or added to the State field's choice list via sys_choice records. Adding custom states requires modifying the incident state model, which affects SLA calculations and reporting.
  • Attachment size limits. ServiceNow's default maximum attachment size is 24 MB (controlled by com.glide.attachment.max_size). SDP files larger than this must be uploaded to a linked file store or compressed. Large attachments may also need multipart/form-data uploads because base64 encoding inflates file size by approximately 33%.
  • Time zone mismatches. SDP stores timestamps in the instance's configured timezone. ServiceNow stores all timestamps in UTC internally and renders them in the user's local timezone. All extracted timestamps must be converted to UTC before loading, or your SLA calculations and audit trails will be wrong. Use Python's pytz library or equivalent for reliable timezone conversion.
  • ServiceNow business rules firing on imported data. Assignment rules, notification rules, and SLA rules can fire on newly inserted records. Disable SLA processing (com.snc.sla.engine.enabled = false) for historical records and suppress auto-generated notifications during bulk loads to prevent false alerts and email storms. Re-enable after loading and before delta sync.
  • Unsupported custom modules. Custom modules built in ServiceDesk Plus that have no equivalent in ServiceNow must be mapped to custom tables (u_ prefix), which may consume table quota depending on your ServiceNow contract.
  • Service request model fidelity. If you compress historical service requests into incidents for simplicity, you reduce build time by approximately 40% but lose catalog structure. This affects reporting (service request vs. incident volume trends), audit trails (catalog approval history), and future automation (catalog-driven workflows). Make this trade-off explicitly — it is permanent.
  • Multi-language content. If your SDP instance stores ticket descriptions or knowledge articles in multiple languages, ServiceNow's internationalization model requires separate knowledge article versions per language, not inline translation. Plan for additional transform work.

Validation and Testing Checklist

Check Method Pass Criteria
Record count by object type Query both systems, compare totals Counts match within 0.1% (accounting for filtered exclusions)
Field accuracy (5% sample) Pull random records by u_legacy_sdp_id, compare field values side by side All mapped fields match source data
User resolution Query incidents for null caller_id where u_legacy_sdp_id is not null Zero null requester fields on records that had a requester in SDP
CMDB relationship integrity Run ServiceNow CMDB Health check + orphan relationship query Zero orphan relationships
Attachment accessibility Open 50 random attachments across modules All files render correctly, file sizes match source
Worklog/conversation threading Open 20 tickets with complex conversation history Chronological order preserved, correct public/private visibility
Knowledge article formatting Review 10 articles in ServiceNow portal No broken images, tables render, internal links resolve
SLA accuracy (historical) Compare SDP resolution times to ServiceNow custom fields Historical SLA data preserved in u_legacy_sla_* fields (not recalculated by ServiceNow)
Notification suppression Verify no outbound emails triggered during load Zero unexpected notifications in sys_email table during load window
Legacy ID searchability Search for 10 random SDP ticket IDs in ServiceNow global search All records found via u_legacy_sdp_id

Compliance Audit Trail

For SOX, HIPAA, or ITIL-audited migrations, produce the following documentation:

  1. Source data inventory — record counts per module, extracted date, extraction method
  2. Hash verification — SHA-256 hashes of all extracted data files, matched against hashes of loaded data
  3. Field mapping document — signed off by the data owner, documenting every source-to-target field mapping and any data transformations applied
  4. Validation report — results of the checklist above, with specific record IDs sampled
  5. Migration log — timestamped log of every API call, batch load, and transform execution with success/failure status
  6. Rollback test results — evidence that the rollback procedure was tested in sub-production

Build In-House or Use a Managed Service?

Build in-house when:

  • Your ticket volume is under 10,000 records
  • You have no CMDB data or only a flat asset list
  • You have an engineer who knows both the SDP API and ServiceNow Import Sets
  • You have a 2 to 3 week window where that engineer can focus entirely on migration
  • Service requests can be simplified instead of rebuilt as catalog objects
  • No compliance audit trail requirements

Use a managed migration service when:

  • Your record count exceeds 50,000 tickets
  • You have a CMDB with multi-level relationships
  • You need to preserve full conversation and worklog history with correct public/private visibility
  • Compliance requirements (SOX, HIPAA, ITIL audit trails) mandate a verified, documented migration with chain-of-custody logging
  • Your ServiceNow instance uses domain separation
  • Your engineering team is already committed to the ServiceNow implementation and cannot absorb migration work without delaying go-live

The hidden cost of DIY is re-migration. Teams that build custom migration scripts frequently end up re-running the migration due to missed edge cases, broken relationships, or field mapping errors discovered after go-live. Each re-run resets the extraction clock by 24 to 48 hours (Cloud) and forces a second round of validation.

ClonePartner has completed ITSM migrations involving complex CMDB hierarchies, multi-site ServiceDesk Plus instances, and ServiceNow Import Set orchestration. Our engineering team handles the rate-limit throttling, relationship ordering, and attachment re-hosting that cause most DIY migrations to stall or produce incomplete data.

Frequently Asked Questions

How long does a ServiceDesk Plus to ServiceNow migration take?
A typical migration takes 2 to 3 weeks for small IT teams with under 10,000 tickets and no CMDB, 4 to 6 weeks for mid-size organizations with basic CMDB, and 6 to 10 weeks for enterprise environments with 100,000+ tickets and complex multi-level CMDB. The extraction phase alone accounts for 30 to 40% of calendar time due to API rate limits.
Can I migrate ServiceDesk Plus to ServiceNow without losing CMDB data?
Yes, but only through API-based extraction. The native CSV export from ServiceDesk Plus does not preserve CMDB relationship data. You must extract CIs and their parent-child relationships via the v3 REST API, map relationship types to ServiceNow's cmdb_rel_type records, and load CIs before relationships to avoid orphaned records.
What data cannot be migrated from ServiceDesk Plus to ServiceNow?
SDP notification history, audit trails of field-level changes, and active SLA timer states have no direct migration path. Native CSV exports also drop worklogs, inline attachments, conversation threading, and CMDB relationships. SDP-specific modules like built-in project management and certain procurement workflows have no equivalent in ServiceNow ITSM without additional module licensing.
How much does a ServiceDesk Plus to ServiceNow migration cost?
Cost depends primarily on record volume, custom field count, and CMDB complexity. A managed migration service for 10,000 tickets without CMDB data typically costs $3,000 to $8,000. Enterprise migrations with 100,000+ records and full CMDB can range from $15,000 to $50,000+. DIY migrations cost less in vendor fees but consume 4 to 8 weeks of senior engineering time.
Does ServiceNow have a native import tool for ServiceDesk Plus?
No. ServiceNow does not offer a built-in connector or migration wizard for ServiceDesk Plus. Data must be loaded through ServiceNow's generic Import Sets and Transform Maps from CSV, XML, or API sources. ManageEngine also does not provide a native export-to-ServiceNow feature.

More from our Blog

Zero-Downtime Help Desk Data Migration: How to Keep Support Running During the Move
Help Desk

Zero-Downtime Help Desk Data Migration: How to Keep Support Running During the Move

This guide details the 3-stage technical process for a zero-downtime help desk migration. Learn how to use an initial bulk data transfer, a continuous delta migration (Change Data Capture), and a seamless final cutover to move platforms without any service interruption. Discover how an engineer-led approach can guarantee a 100% accurate, 50x faster migration.

Raaj Raaj · · 6 min read