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.
- Years of issues, comments, and attachments locked in Jira's proprietary format
- Complex relationships between issues (blocks, relates to, parent/child hierarchies)
- User assignments and watchers need to be mapped to new system
- Custom fields that track original Jira IDs for reference
- 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
- Fetch Jira Issues: Query Jira API for all issues in source project with JQL
- Check Existing: Search OpenProject for issues with matching Jira ID custom field
- Create/Update: Create new work packages or update existing ones
- Migrate Attachments: Download from Jira, upload to OpenProject
- Migrate Comments: Transfer comment threads with author info
- Add Watchers: Map Jira watchers to OpenProject users
- Create Relationships: Link issues using OpenProject's relation API
- 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:
- Create a text custom field in OpenProject (e.g., "Jira ID")
- Tool stores original Jira issue key (e.g., "PROJ-123") in this field
- Before creating issues, tool searches for existing work packages with matching Jira ID
- If found: update existing work package instead of creating duplicate
- 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_IDThe Relationship Migration Challenge
Jira and OpenProject have different relationship models. The tool maps between them:
| Jira Link Type | OpenProject Relation |
|---|---|
| Blocks | blocks |
| Is blocked by | blocked (reverse) |
| Relates to | relates |
| Duplicates | duplicates |
| Is duplicated by | duplicated |
| Parent/Sub-task | parent (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_IDThe interactive mode guides you through project selection and confirms before making changes. For automated pipelines, use command-line arguments to skip prompts.
Technical Highlights
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.