Documentation Index
Fetch the complete documentation index at: https://ekso.dev/llms.txt
Use this file to discover all available pages before exploring further.
ekso migrate jira pulls projects, issues, comments, worklogs, attachments, and links from Atlassian Jira (Cloud) into your Ekso tenant. Two commands — collect and apply. Read Migrate overview and Before you start first.
What gets imported
| Jira concept | Ekso shape |
|---|
| Project | DataContainer (Code = ACME, Name = ACME Platform) |
| Issue (any type — Bug, Task, Story, Epic) | DataItem |
| Comment | DataAnnotation |
| Attachment | DataFile (multipart upload) |
| Worklog | DataItem.Time[] (in the same item POST) |
| Issue link (relates, blocks, subtask, …) | DataLink |
| Sprint (GreenHopper) | DataCycle |
| Fix Version | DataCycle |
| Component | ConfigLabel (prefix component:) + item Tags |
| User (assignee, reporter, commenter) | DataUser (matched or minted) |
| Story Points custom field | DataItem.Field[] (via --field-map) |
| Other custom fields | DataItem.Field[] (via --field-map) or Meta |
| Affects Version | DataItem.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.
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.
- An Atlassian API token (free).
- Your Atlassian site URL — e.g.
https://acme.atlassian.net.
Add a jira block to your migration.config.json:
{
"ekso": { "tenant": "acme", "apiKey": "ek_live_..." },
"source": "jira",
"jira": {
"url": "https://acme.atlassian.net",
"username": "[email protected]",
"apiToken": "ATATT3..."
}
}
Or use the env-var override EKSO_MIGRATE_JIRA_TOKEN for CI use cases.
Step 1 — list projects
Verify your credentials work and see what Jira shows you:
ekso migrate jira list-projects \
--config migration.config.json \
--tenant acme
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 Atlassian credentials are wrong — check the API token. Pass --exclude-closed to filter projects in archived state.
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 \
--tenant acme
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.
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 \
--tenant acme \
--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 \
--tenant acme
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:
| Jira | Ekso |
|---|
| Sprint (GreenHopper) | DataCycle (one cycle per sprint, items linked) |
| Fix Version | DataCycle (sprint-shaped: name + dates + member items) |
| Affects Version | DataItem.Meta.jira_affects_versions[] |
| Component | ConfigLabel (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.
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
| Symptom | Fix |
|---|
exit 3 — Jira credentials invalid | Regenerate the API token. Check the email matches the token owner. |
exit 7 — Jira rate-limit exceeded | Wait a few minutes; Atlassian’s rate limits are per-tenant. Re-run with --resume. |
| Item created with empty body | Atlassian returned no rendered HTML for an ADF description. Original ADF is preserved in Meta.jira_description_html. |
Custom field unknown to field-map | Check 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