Skip to main content
ekso migrate jira pulls projects, issues, comments, worklogs, attachments, and links from Atlassian Jira — Cloud, Data Center, or Server — into your Ekso tenant. Two commands — collect and apply. Read Migrate overview and Before you start first.

What gets imported

Jira conceptEkso shape
ProjectDataContainer (Code = ACME, Name = ACME Platform)
Issue (any type — Bug, Task, Story, Epic)DataItem
CommentDataAnnotation
AttachmentDataFile (multipart upload)
WorklogDataItem.Time[] (in the same item POST)
Issue link (relates, blocks, subtask, …)DataLink
Sprint (GreenHopper)DataCycle
Fix VersionDataCycle
ComponentConfigLabel (prefix component:) + item Tags
User (assignee, reporter, commenter)DataUser (matched or minted)
Story Points custom fieldDataItem.Field[] (via --field-map)
Other custom fieldsDataItem.Field[] (via --field-map) or Meta
Affects VersionDataItem.Meta.jira_affects_versions[] (lossless)
Authoring fidelity is preserved: every comment, every worklog, every item is attributed to the original Atlassian user (matched by email, or minted via identity resolution).

What does NOT get imported

  • Workflow definitions / transition rules. The migrator snapshots the current status of each issue. Build the workflow on the Ekso side.
  • Dashboards, filters, JQL queries. Migrate operationally, then re-author in Ekso.
  • Automations (Jira Automation rules). Re-author as Ekso rules.
  • Permission schemes / project roles. Configure access on the Ekso side.
  • Brand customisation, themes, project icons. Atlassian-specific.

Editions — Cloud vs Data Center / Server

The CLI detects your Jira deployment automatically by calling GET /rest/api/2/serverInfo on first use — no configuration needed in the common case.
EditionDetectionAuth
Cloud (cloud)deploymentType: Cloudusername (email) + apiToken
Data Center (datacenter)deploymentType: Server (hosted DC)personalAccessToken
Server (server)deploymentType: Server (on-prem)personalAccessToken
To override detection, set jira.edition in your config to one of auto (default), cloud, datacenter, or server. You can also pass --edition <value> directly on the list-projects and collect commands.

Before you start

Pre-flight checklist on top of the general one:
  • An Atlassian account with read access to the projects you want to migrate.
  • Your Jira URL.
  • Cloud: An Atlassian API token (free). Site URL is https://acme.atlassian.net.
  • Data Center / Server: A Personal Access Token (PAT) — create one in your profile under Security → Personal Access Tokens. Requires Jira 8.14 or later; attachment download requires Jira 8.17 or later.

Cloud config

{
  "ekso": { "url": "https://ekso.acme.com", "apiKey": "ek_live_..." },

  "source": "jira",

  "jira": {
    "url": "https://acme.atlassian.net",
    "username": "[email protected]",
    "apiToken": "ATATT3..."
  }
}
Use EKSO_MIGRATE_JIRA_TOKEN to pass the API token via environment variable instead.

Data Center / Server config

{
  "ekso": { "url": "https://ekso.acme.com", "apiKey": "ek_live_..." },

  "source": "jira",

  "jira": {
    "url": "https://jira.mycompany.com",
    "edition": "datacenter",
    "personalAccessToken": "..."
  }
}
Use EKSO_MIGRATE_JIRA_PAT to pass the PAT via environment variable instead.

Data Center — comments and descriptions

On Data Center / Server, issue descriptions and comments are returned as server-rendered HTML. The migrator imports them as-is; formatting is preserved.

Data Center — SSO-fronted instances and attachments

If your Data Center instance sits behind SSO (SAML/OIDC), attachment downloads require a browser session that the CLI cannot always establish automatically. When a session cannot be obtained for a specific attachment, the download is skipped and logged — the rest of the migration continues. Check the collect output for any attachment skipped lines and download those files manually if needed.

Step 1 — list projects

Verify your credentials work and see what Jira shows you:
ekso migrate jira list-projects \
    --config migration.config.json \
    --url https://ekso.acme.com
Sample output:
NAME              KEY    ID       LEAD
ACME Platform     ACME   10001    Jane Doe
ACME Mobile       ACMEM  10002    John Smith
If this exits with code 3, your credentials are wrong — check the API token (Cloud) or PAT (Data Center/Server). Pass --exclude-closed to filter projects in archived state. Pass --edition <cloud|datacenter|server> to override auto-detection.

Step 2 — collect

Pull a single project’s issues, comments, worklogs, and attachments into a local SQLite cache:
ekso migrate jira collect \
    --config migration.config.json \
    --project ACME \
    --url https://ekso.acme.com
--project takes the Jira project Key (e.g. ACME), not the project Name (“ACME Platform”). The key is shown in the KEY column of list-projects above. Repeat --project for multiple. Sample run:
fetching projects... 1 fetched
fetching ACME items... 1247/1247  ok
fetching comments... 4083/4083  ok
fetching worklogs... 891/891  ok
fetching attachments... 312/312  ok
saved cache: ~/.ekso/migrate/jira-2026-04-29T143205.sqlite
Useful flags:
  • --no-attachments — skip binary download. ~10x faster on attachment-heavy projects.
  • --no-comments — skip comments.
  • --exclude-closed — JQL-filter out resolved issues at the source.
  • --resume — pick up where a killed collect left off.
  • --edition <cloud|datacenter|server> — override the auto-detected edition.
Expect roughly 200 issues/minute on a good network. A 10,000-issue project takes ~50 minutes including comments and attachments.

Step 3 — dry-run apply

Before writing anything to your Ekso tenant, walk the cache and see what would happen:
ekso migrate jira apply \
    --config migration.config.json \
    --process proc_engineering \
    --url https://ekso.acme.com \
    --dry-run
Sample output:
DRY-RUN — no writes.
would create:  1 container, 47 users, 1247 items, 4083 annotations,
               312 files, 89 links, 8 cycles
field-map check: ok (3 process fields would be auto-created)
If field-map check fails (e.g. picker without a value list), exit code is 2 and apply won’t run for real until you fix the YAML.

Step 4 — apply for real

ekso migrate jira apply \
    --config migration.config.json \
    --process proc_engineering \
    --url https://ekso.acme.com
Sample run:
applying container ACME...               ok
applying users (47)...                   ok (45 created, 2 matched)
applying items (1247)...                 ok (1247 created)
applying annotations (4083)...           ok
applying files (312)...                  ok
applying links (89)...                   ok
applying cycles (8)...                   ok (5 sprints, 3 fix-versions)
done in 7m43s — exit 0
If the run is interrupted, re-run with --resume:
ekso migrate jira apply \
    --config migration.config.json \
    --process proc_engineering \
    --resume

Identity resolution for Jira

Atlassian users have email — --user-strategy match-or-create (the default) is reliable. Source authors are matched against your Ekso tenant; users without a match are minted with no invite email. Read Identity resolution for the full mechanics.

Custom fields for Jira

Story Points, Sprint, custom Severity — these are Jira customfield_* fields. Map them to Ekso process fields with a migration.fields.yaml:
jira:
  customfield_10026: { ekso: StoryPoints, kind: decimal }
  customfield_10018: { ekso: Sprint,      kind: text }
  customfield_10031:
    ekso: Severity
    kind: picker
    picker:
      Critical: P0
      High:     P1
      Medium:   P2
      Low:      P3
Pass it to apply:
ekso migrate jira apply \
    --config migration.config.json \
    --process proc_engineering \
    --field-map migration.fields.yaml
ProcessFieldApplier runs first; any field referenced by the YAML that doesn’t exist on proc_engineering is auto-created via POST /api/field before any item write. See Field mapping for the full format and how to discover your custom-field IDs. Without --field-map, custom fields fall through to DataItem.Meta losslessly (e.g. Meta.jira_customfield_10026).

Sprints, Fix Versions, Components

Per the migrator’s design, every Jira concept maps. There are no opt-in flags:
JiraEkso
Sprint (GreenHopper)DataCycle (one cycle per sprint, items linked)
Fix VersionDataCycle (sprint-shaped: name + dates + member items)
Affects VersionDataItem.Meta.jira_affects_versions[]
ComponentConfigLabel (component:Backend) + DataItem.Tags
Release (a closed Fix Version)DataCycle
Cycles attach to a board on the Ekso side. Pass --board <BOARD_ID> if the tenant has more than one board; the CLI auto-discovers when there’s exactly one.

Issue type → Process

Multiple Jira issue types (Bug, Task, Story, Epic) feed into a single Ekso DataProcess per apply invocation. The mapping is one-way; the issue type is preserved in DataItem.Meta.jira_issuetype. If you need separate processes per issue type, run apply multiple times with different --process values and JQL-filtered caches.

Iron rule — Atlassian’s date format

Jira returns timestamps in the form 2024-08-21T16:33:21.000+0000 — note the +0000 offset has no colon. The standard .NET DateTime parser trips on this. The CLI’s JiraDateTimeNormaliser handles it correctly, and there’s a regression test pinning the behaviour. If you ever see “Date format unparseable” in apply output, the cache was generated by an older CLI version. Re-collect with the latest CLI.

Troubleshooting Jira-specific issues

SymptomFix
exit 3 — Jira credentials invalid (Cloud)Regenerate the API token. Check the email matches the token owner.
exit 3 — Jira credentials invalid (DC/Server)Regenerate the PAT. Confirm Jira version is 8.14 or later.
exit 7 — Jira rate-limit exceededWait a few minutes; Atlassian’s rate limits are per-tenant. Re-run with --resume.
Item created with empty bodyAtlassian returned no rendered HTML for an ADF description. Original ADF is preserved in Meta.jira_description_html.
attachment skipped lines in DC collect outputSSO is fronting the instance and a download session could not be established. Download those attachments manually.
Custom field unknown to field-mapCheck the customfield_* ID exists on this Jira tenant.
See Troubleshooting for the full per-source error table.

Why migrate to Ekso

Once you’ve moved a Jira project to Ekso, you get financial intelligence (cost / profitability) and AI-native primitives (MCP) that don’t exist on the Jira side. See Ekso vs Jira for the broader comparison.

Where to next