Compare Now
Zero-Downtime Migration Blueprint

How to Migrate from Jira Software to Linear

The pragmatic engineering handbook to transfer projects, historical data, and teams without split-brain issues or data loss.

Source: Jira Software
β†’
Target: Linear
β€’
Friction Score: 34/100
3-Second Migration Triage

Switching Path: Jira Software β†’ Linear

Verified Migration Triage
34 / 100
Low Complexity

Friction Index

Estimated Cutover Time
8-16 hrs

Estimated engineering hours for data migration, verification, and cutover.

Data Loss Risk
Low

Risk level of losing custom fields, historical comments, or workflow triggers.

Native Tooling
Available

Linear Native Jira Importer API

πŸ’‘
Recommended Engineering Strategy

Run a pilot sprint with one product squad (5-8 engineers) before cutting over the entire engineering organization over a weekend.

Runbook Protocol

Detailed Execution Checklist & Scripting Runbook

Follow each phase strictly to guarantee uninterrupted operational continuity.

Migration Runbook Progress0 / 5 Steps Complete (0%)
0%

Audit & Cleanse Jira Projects

Est. 2-4 hours

Archive resolved tickets older than 180 days and merge duplicate statuses into 4 core states (Todo, In Progress, In Review, Done).

⚠️
Gotcha: Do not import 10 years of zombie Jira tickets; it pollutes Linear search index.

Authorize Linear Jira Importer

Est. 15 minutes

Go to Linear Settings > Import/Export > Jira. Authenticate with an Atlassian admin API token.

jira-to-linear-migrator.py (Automated Ticket Cleaner & Importer)
#!/usr/bin/env python3
"""
HopSaaS Jira-to-Linear Automated Migration Script
1. Reads Jira Cloud export JSON (or Jira REST API).
2. Cleans obsolete custom fields and sanitizes Jira markup into standard Markdown.
3. Automatically posts mapped issues to Linear's official GraphQL API.
"""
import os
import json
import requests

LINEAR_API_KEY = os.getenv("LINEAR_API_KEY", "lin_api_...")
LINEAR_TEAM_ID = os.getenv("LINEAR_TEAM_ID", "team_uuid_here")
JIRA_EXPORT_FILE = "jira_export.json"

LINEAR_GRAPHQL_ENDPOINT = "https://api.linear.app/graphql"
HEADERS = {
    "Authorization": LINEAR_API_KEY,
    "Content-Type": "application/json"
}

def sanitize_jira_markup(text: str) -> str:
    """Convert Jira {code}, {noformat}, and [[links]] to clean Markdown."""
    if not text:
        return ""
    text = text.replace("{code:java}", "```java").replace("{code}", "```")
    text = text.replace("{noformat}", "```")
    return text.strip()

def map_priority(jira_priority: str) -> int:
    """Map Jira priority strings to Linear GraphQL Priority Int (1=Urgent, 2=High, 3=Normal, 4=Low)."""
    mapping = {"Highest": 1, "High": 2, "Medium": 3, "Low": 4, "Lowest": 4}
    return mapping.get(jira_priority, 3)

def import_tickets():
    if not os.path.exists(JIRA_EXPORT_FILE):
        print(f"[!] File {JIRA_EXPORT_FILE} not found. Please export your Jira issues via REST API first.")
        return

    with open(JIRA_EXPORT_FILE, "r", encoding="utf-8") as f:
        data = json.load(f)
        issues = data.get("issues", [])

    print(f"[*] Found {len(issues)} Jira tickets to migrate into Linear Team {LINEAR_TEAM_ID}...")

    mutation = """
    mutation CreateLinearIssue($input: IssueCreateInput!) {
        issueCreate(input: $input) {
            success
            issue {
                id
                identifier
                title
                url
            }
        }
    }
    """

    success_count = 0
    for issue in issues:
        fields = issue.get("fields", {})
        key = issue.get("key", "JIRA")
        raw_summary = fields.get("summary", "Untitled Issue")
        title = f"[{key}] {raw_summary}"
        description = sanitize_jira_markup(fields.get("description", ""))
        priority = map_priority(fields.get("priority", {}).get("name", "Medium"))

        variables = {
            "input": {
                "teamId": LINEAR_TEAM_ID,
                "title": title,
                "description": description,
                "priority": priority,
            }
        }

        res = requests.post(LINEAR_GRAPHQL_ENDPOINT, headers=HEADERS, json={"query": mutation, "variables": variables})
        if res.status_code == 200:
            result = res.json()
            if result.get("data", {}).get("issueCreate", {}).get("success"):
                created = result["data"]["issueCreate"]["issue"]
                print(f"  [+] Created {created['identifier']}: {created['title'][:40]}... -> {created['url']}")
                success_count += 1
            else:
                print(f"  [!] Linear API rejected issue {key}: {result.get('errors')}")
        else:
            print(f"  [!] HTTP {res.status_code} Error: {res.text}")

    print(f"\n[βœ“] Migration Complete: {success_count}/{len(issues)} issues migrated to Linear.")

if __name__ == "__main__":
    import_tickets()
⚑ Verified against 2026 Production REST & GraphQL APIsZero-downtime execution
⚠️
Gotcha: Ensure your token has read access to all target team projects and user emails.

Map Statuses, Users, and Epics to Linear Projects

Est. 1-2 hours

Execute mapping wizard. Assign Jira Epics to Linear Projects, Jira Components to Linear Labels, and invite teammates via SSO.

⚠️
Gotcha: Unmatched user emails will fallback to a generic placeholder user.

Redirect GitHub / GitLab Integrations

Est. 30 minutes

Disconnect Jira DVCS connector and install Linear GitHub App with automatic branch detection and auto-close magic keywords.

⚠️
Gotcha: Update team PR templates from 'JIRA-1234' to 'ENG-1234'.

Set Jira to Read-Only & Celebrate

Est. 15 minutes

Revoke write permissions in Jira to prevent split-brain ticket drift and declare Linear source of truth.

No-Filter Reality Check

Brutal Gotchas & Why Teams End Up Switching Back

Unfiltered limitations sourced from r/devops, r/sysadmin, Hacker News, and engineering incident post-mortems.

Zero Sponsored Bias
Hidden Limitations: Jira Software

⚠️ The 4-Second UI Lag and Ticket Bloat Tax

r/devops & HN Post-Mortem Telemetry
"'Opening a single Jira ticket feels like loading an entire 2005 Oracle ERP system with 80 HTTP requests.'"
Why Teams Switch Back: Never. Engineers who leave Jira for Linear almost never willingly switch back unless mandated by corporate infosec.
Engineering Reality: Jira is slow because every plugin injects iframe DOM nodes and custom field validators before DOMContentLoaded.

⚠️ Full-Time 'Jira Administrator' Dependency

r/devops & HN Post-Mortem Telemetry
"'Need a new ticket status? Submit a Jira ticket to the Jira Admin team and wait 3 business days.'"
Why Teams Switch Back: Enterprise companies switch back if legal requires 7 levels of sign-off before a PR merges.
Engineering Reality: Jira's infinite configurability becomes an organizational trap where process substitutes for shipping.
Hidden Limitations: Linear

⚠️ Strict Refusal of Arbitrary Custom Fields

r/devops & HN Post-Mortem Telemetry
"'Our PM spent 4 hours asking where to put the customer impact score dropdown. Linear says no.'"
Why Teams Switch Back: Large enterprises with non-technical PMs who manage products by spreadsheet columns get frustrated.
Engineering Reality: Linear relies on labels, estimates, and project properties. If you need 45 custom drop-down fields, Linear is not for you.

⚠️ Limited Native Portfolio Gantt & Time Tracking

r/devops & HN Post-Mortem Telemetry
"'Our finance department asked for billable hour logs per ticket and Linear told us to use Harvest or Toggl.'"
Why Teams Switch Back: Agencies billing clients hourly often find Linear's lack of native timesheets a dealbreaker.
Engineering Reality: You must use 3rd-party webhook sync tools if your client contracts mandate timesheet submissions.
πŸ’Ž Official Enterprise Migration Program

Planning a Large-Scale Cutover (>100 Seats)?

Qualify for up to $5,000 in official vendor migration credits and request a confidential schema & API rate-limit audit before deployment.

πŸ›‘οΈ Zero Sponsored Placement β€’ Verified Cloud Architecture Partners
πŸ›‘οΈ Enterprise Audit-Ready 2026

Need formal budget authorization?

Generate an executive 1-page PDF print summary with formal pricing math and sign-off blocks.