Migrating off Jira — phase by phase.
Jira migrations are about three things: extracting via the Cloud REST API (which paginates differently for issues than for most other resources), faithfully rebuilding the workflow + scheme spaghetti as state machines, and translating JQL searches and Marketplace-app bills into first-class features in the new product. Issue keys (PROJ-1234) are preserved everywhere so external links, commits, and PR references keep resolving.
The phases, tuned to Jira
Each phase below is the Jira-specific version of our standard playbook. Same shape every engagement, different specifics per SaaS.
Workflow + scheme audit
2-3 weeksEvery Jira instance has accumulated a forest of workflows, screen schemes, permission schemes, notification schemes and field configurations. We inventory ruthlessly — most teams collapse 30+ workflows into 5-6 once duplicates and unused ones are removed.
✓Export every workflow definition + transition rule via the REST API✓List every screen scheme, permission scheme, notification scheme, field configuration scheme✓Inventory active Marketplace apps and what each one actually does (most teams have 3-6 they pay for; 1-2 are doing real work)✓Catalogue saved JQL filters — these become saved views in the new product✓Identify the integrations (GitHub, GitLab, Slack, OpsGenie, Statuspage) that need to keep working through migrationYou walk away withA Workflow + Scheme Inventory + a Marketplace-app shortlist (rebuild / replace / drop).
Schema + issue-key strategy
1 weekIssues become a properly-typed table with the issue key (PROJ-1234) preserved everywhere. Custom fields stop being string blobs. Workflows become state machines defined in TypeScript and reviewed in PRs.
✓Design `issues` table with `jira_key` column (indexed) + native columns for the top 20 fields✓Custom fields get sensible types (Date, Money, Decimal, Enum) instead of cf[10042] strings✓Workflow definitions as TypeScript state machines (transitions, validators, post-functions)✓Permission scheme → 4-6 named roles in code✓Plan a JQL-equivalent query layer in Postgres (most JQL clauses are 1:1 to SQL with the right indexes)You walk away withSchema migrations + workflow state machines in TypeScript + the issue-key preservation strategy.
Extract via REST API
1-2 weeksJira Cloud's REST API paginates issues via `?startAt` + `maxResults` (default 50, max 100). The search endpoint is where you'll spend most of the extract budget — chunk by project + by date range to stay under the rate limits.
✓Authenticate via OAuth 2.0 (3LO) or API token with HTTP Basic✓Iterate `/rest/api/3/search` per project with JQL `project = X ORDER BY created`✓Pull each issue's comments, worklogs, changelog, attachments separately (the search response is shallow)✓Extract sprints + versions + components per project✓Pull users, groups, project roles and permissions for the RBAC mapping✓Save the raw JSON — it's useful evidence during reconciliationYou walk away withA re-runnable extract pipeline + a reconciliation report comparing issue counts per project.
Build + weekly demos
5-8 weeksIssues, boards, JQL-equivalent search, automation rules and dashboards rendered server-side. Time-tracking and roadmaps stop being paid Marketplace apps and become first-class columns.
✓Issues list + Kanban + sprint views — virtualised grid for the 50k-issue case✓JQL-equivalent search via Postgres full-text + structured filters; saved filters become URL state✓Automation rules as TypeScript functions with a real audit trail (the Jira automation rule cap stops being a thing)✓Time-tracking as a column on the issue table (no Tempo / Clockwork app needed)✓Roadmap / Gantt as a derived view over due dates + dependencies (no Advanced Roadmaps subscription)✓Dashboards rendered server-side from real SQLYou walk away withA working tracker on staging that your engineering team uses for one full sprint.
Parallel run + reconciliation
2-3 weeksBoth systems live for two-three weeks. Issues created in Jira sync nightly into the new product; webhooks from GitHub / GitLab / Slack fire into both during the ramp.
✓Daily incremental sync from Jira via the `updated >= -1d` JQL filter✓Bridge integrations (GitHub commit messages, Slack notifications) to both systems✓Daily reconciliation: open vs done counts per project, comment-count drift, attachment integrity✓Train engineers in two 45-minute sessions, recorded for the rest✓Pin the issue-key strategy in commit messages — `PROJ-1234` still resolves on both sidesYou walk away withA reconciliation dashboard + a green sprint demo from the new product.
Cutover + Jira read-only
1 day + 90-day fallbackJira goes read-only on a Tuesday morning, GitHub / Slack integrations point only at the new product, Atlassian Marketplace apps get cancelled the same week.
✓Cut SSO + bookmark redirects to the new tracker✓Lock Jira to read-only (revoke project-admin and edit permissions)✓Cancel Atlassian Marketplace apps in writing — the bill drops the same month✓Hold a 90-day Jira read-only window for compliance / regret / audit✓Cancel the Atlassian Cloud subscription auto-renewalYou walk away withCutover Runbook + cancelled Marketplace subscriptions + a quiet inbox where the renewal email used to land.
The Jira APIs we'd actually hit
Concrete endpoints we use to extract your data during the parallel-run phase. We keep the extract scripts — they're useful at every renewal.
GET /rest/api/3/search?jql={jql}&startAt={n}&maxResults=100GET /rest/api/3/issue/{issueKeyOrId}?expand=changelog,renderedFieldsGET /rest/api/3/issue/{issueKeyOrId}/commentGET /rest/api/3/workflow/searchGET /rest/api/3/project/searchGET /rest/api/3/users/searchGET /rest/agile/1.0/board/{boardId}/sprintPOST https://auth.atlassian.com/oauth/tokenThe Jira-specific gotchas
Things we've learnt the hard way (or that the documentation understates). We'll surface these on the kickoff call so nobody is surprised in week 6.
- ⚠Issues paginate via `?startAt` + `maxResults` (default 50, max 100) — the search response is shallow, so each issue needs a follow-up call for comments/changelog/worklogs. Plan for 5-10x more API calls than 'issue count'.
- ⚠Rate limits are per-tenant and burst-tolerant but the search endpoint is throttled harder than most. Use exponential backoff on 429s, parallelise by project not by global issue stream.
- ⚠Custom fields are exposed via opaque IDs (`customfield_10042`) — you need a separate metadata call to get the field name + type, and the type can be ambiguous (a number field exposed as string).
- ⚠JQL has clauses with no direct SQL equivalent (`updated`, `worklogAuthor`, `issueFunction in ...`) — most translate cleanly but a few need bespoke handling. Inventory saved JQL filters in Phase 1 so nothing surprises in Phase 4.
- ⚠Workflow post-functions and validators include both built-in and Marketplace-app-provided ones. The Marketplace ones won't extract cleanly — rebuild the logic from the rule inventory.
- ⚠Atlassian Marketplace apps add data to issues via custom fields or external storage. Inventory which apps store data IN Jira (extractable) vs. OUTSIDE Jira (separate extract per app).
- ⚠Linked issues, parent/epic links and sub-tasks use different relationship models — preserve all three in the new schema or you'll lose the hierarchy view your engineers rely on.
- ⚠Permission schemes + project roles + groups can grant access through multiple paths. Map every actual permission a user has today and reconcile against the new RBAC before cutover.
What stays where it is
Migrations work because they're scoped honestly. Here's what we don't move — by design.
- ·Atlassian Marketplace apps — replaced by first-class features or dropped
- ·Jira Service Management — separate scoping conversation (it's a different product, not in Jira Software scope)
- ·Bitbucket repos — keep them where they are or migrate to GitHub separately
- ·Confluence — paired separately (it's its own SaaS to kill, see /confluence/migration)
- ·Atlassian Intelligence / AI add-ons — replaced with Claude/GPT against your own data
- ·Advanced Roadmaps as a separate product — folded into the new tracker as a view over due dates + dependencies
Get a Jira-shaped migration plan.
Tell us your seat count, contract end date, and the integrations you can't lose. We'll come back within a business day with a fixed-price scope and a timeline tuned to your renewal.
Scope a Jira migration
One business day. NDA + DPA on request.