Back to Home

Building OpenProject Jira Importer

Building OpenProject Jira Importer

An Open-Source Migration Tool for Escaping Jira Without Losing Your Data

The Problem: Jira Lock-In Is Expensive

Jira is the default choice for project management, but Atlassian's pricing keeps climbing. For many teams, switching to a self-hosted solution like OpenProject could save thousands of dollars annually. But there's a catch: migration.

  1. Years of issues, comments, and attachments locked in Jira's proprietary format
  2. Complex relationships between issues (blocks, relates to, parent/child hierarchies)
  3. User assignments and watchers need to be mapped to new system
  4. Custom fields that track original Jira IDs for reference
  5. Manual migration would take weeks and guarantee data loss

Existing migration tools were either expensive enterprise services or incomplete scripts that only handled basic fields. I needed a comprehensive tool that would migrate everything.

So I built one and open-sourced it for the community.

The Vision: Complete Migration Without Data Loss

I set out to build OpenProject Jira Importer: a CLI tool that would handle every aspect of migration with minimal manual intervention. The core principles:

Preserve Everything

Issues, descriptions, priorities, statuses, attachments, comments, watchers—nothing left behind. Your project history is your knowledge base.

Maintain Relationships

Parent-child hierarchies, blocks/blocked by, relates to—all issue relationships preserved exactly as they were in Jira.

Incremental Migration

Track original Jira IDs in custom fields. Run migrations multiple times—tool detects existing issues and updates instead of duplicating.

User Mapping

Generate user mappings automatically. Map Jira users to OpenProject users so assignments and watchers transfer correctly.

What Gets Migrated

Issues & Descriptions

Full issue content with descriptions, priorities, and statuses mapped to OpenProject equivalents.

Attachments

All file attachments downloaded from Jira and uploaded to OpenProject work packages.

Comments

Comment threads preserved with author attribution and timestamps.

Relationships

Issue links (blocks, relates to, duplicates) converted to OpenProject relations.

Hierarchies

Parent-child issue structures preserved as OpenProject work package hierarchies.

Watchers

Users watching issues mapped and added as watchers in OpenProject.

The Tech Stack: Simple and Effective

Node.js + JavaScript

No build step, no compilation—just node migrate.js and go. JavaScript's async/await makes API orchestration readable. Axios handles HTTP requests with proper error handling and retry logic.

Inquirer.js for Interactive CLI

No complex configuration files. Run the tool, select source and target projects from interactive menus, confirm existing issue handling, and watch the migration proceed. Progress indicators show real-time status for each issue.

Environment Variables for Config

All credentials stored in .env file: Jira host, API token, OpenProject URL, API key. Copy the example file, fill in your values, and you're ready to migrate. No sensitive data hardcoded.

The Architecture: Modular API Clients

The tool separates concerns into dedicated API client modules:

  • jira-client.js: Handles all Jira API calls—fetching issues, comments, attachments, users, and relationships
  • openproject-client.js: Manages OpenProject API operations—creating work packages, uploading attachments, setting relations
  • migrate.js: Main orchestrator that coordinates the migration workflow
  • migrate-relationships.js: Dedicated script for relationship migration (run separately to handle ordering)
  • migrate-parents.js: Handles parent-child hierarchies specifically
  • user-mapping.js: User lookup table mapping Jira users to OpenProject users

The Migration Flow

  1. Fetch Jira Issues: Query Jira API for all issues in source project with JQL
  2. Check Existing: Search OpenProject for issues with matching Jira ID custom field
  3. Create/Update: Create new work packages or update existing ones
  4. Migrate Attachments: Download from Jira, upload to OpenProject
  5. Migrate Comments: Transfer comment threads with author info
  6. Add Watchers: Map Jira watchers to OpenProject users
  7. Create Relationships: Link issues using OpenProject's relation API
  8. Set Hierarchies: Establish parent-child relationships

The Incremental Migration Pattern

Real-world migrations rarely happen in one shot. Teams continue working in Jira while migration is tested. The tool handles this with a custom field pattern:

  1. Create a text custom field in OpenProject (e.g., "Jira ID")
  2. Tool stores original Jira issue key (e.g., "PROJ-123") in this field
  3. Before creating issues, tool searches for existing work packages with matching Jira ID
  4. If found: update existing work package instead of creating duplicate
  5. If not found: create new work package with Jira ID populated

This means you can run the migration as many times as needed during testing or parallel operation periods. The custom field also serves as a permanent reference back to the original Jira issue.

# Run migration - safe to run multiple times
node migrate.js PROJECT_KEY OPENPROJECT_ID

# Migrate specific issues only
node migrate.js PROJECT_KEY OPENPROJECT_ID ISSUE-1,ISSUE-2,ISSUE-3

# Run relationships separately (after all issues exist)
node migrate-relationships.js PROJECT_KEY OPENPROJECT_ID

The Relationship Migration Challenge

Jira and OpenProject have different relationship models. The tool maps between them:

Jira Link TypeOpenProject Relation
Blocksblocks
Is blocked byblocked (reverse)
Relates torelates
Duplicatesduplicates
Is duplicated byduplicated
Parent/Sub-taskparent (hierarchy)

Important: Run parent-child migration (migrate-parents.js) before relationship migration. OpenProject doesn't allow both hierarchies and "part of"/"includes" relations between the same work packages.

The Challenges and Solutions

1. Jira API Rate Limiting

Jira Cloud limits API requests. Large projects hit these limits during attachment downloads. Solution: built-in delays between requests and automatic retry with exponential backoff on rate limit errors.

2. OpenProject API Quirks

OpenProject's API requires specific content types and has strict validation. Attachment uploads need proper form-data encoding. The openproject-client module abstracts these details with consistent error handling.

3. User Mapping Complexity

Jira and OpenProject have different user ID systems. The generate-user-mapping.js script creates a mapping file that you can review and edit before migration. Users not mapped are skipped gracefully with warnings.

4. Duplicate Detection

Running migration multiple times could create duplicates. The custom field lookup pattern prevents this, but edge cases exist (like deleted and recreated issues). The remove-duplicates.js script helps clean up if needed.

Getting Started

# Clone the repository
git clone https://github.com/dotnetfactory/openproject-jira-importer.git
cd openproject-jira-importer

# Install dependencies
npm install

# Copy and configure environment variables
cp .env.example .env
# Edit .env with your Jira and OpenProject credentials

# Generate user mapping (optional but recommended)
npm run generate-mapping

# Run interactive migration
node migrate.js

# Or migrate specific project with arguments
node migrate.js JIRA_PROJECT_KEY OPENPROJECT_ID

# Migrate relationships after issues exist
node migrate-relationships.js JIRA_PROJECT_KEY OPENPROJECT_ID

# Migrate parent-child hierarchies
node migrate-parents.js JIRA_PROJECT_KEY OPENPROJECT_ID

The interactive mode guides you through project selection and confirms before making changes. For automated pipelines, use command-line arguments to skip prompts.

Technical Highlights

100% JavaScript—no build step needed
Interactive CLI with Inquirer.js
Incremental migration via custom field tracking
Full data preservation—attachments, comments, relations
User mapping with manual override support
Rate limit handling with exponential backoff
Hierarchy preservation for sub-tasks
MIT licensed—free for any use

The Results: Days to Hours

Manual Migration

  • • Export issues: 2 hours
  • • Manual data entry: 40+ hours
  • • Attachment re-upload: 8 hours
  • • Recreate relationships: 16 hours
  • Total: 60+ hours + data loss risk

With This Tool

  • • Setup: 15 minutes
  • • User mapping review: 30 minutes
  • • Run migration: 1-2 hours
  • • Verify results: 30 minutes
  • Total: ~3 hours + zero data loss

That's a 95% time reduction and complete data preservation.

Open Source and Free Forever

This tool is released under the MIT License. Use it for personal projects, enterprise migrations, or build commercial services on top of it. No restrictions, no licensing fees.

Contributions are welcome! If you encounter edge cases, add features, or improve error handling, submit a pull request. The goal is to make Jira-to-OpenProject migration accessible for everyone.

Tech Stack Summary

Runtime: Node.js

Language: JavaScript (ES6+)

HTTP Client: Axios with retry logic

CLI Interface: Inquirer.js for interactive prompts

Configuration: dotenv for environment variables

File Handling: form-data for multipart uploads

APIs: Jira REST API v3, OpenProject API v3

License: MIT

Need Help With Your Migration?

While the tool is free and open-source, complex migrations sometimes need expert guidance. If you need custom modifications, enterprise support, or a managed migration service, let's connect.