A production-ready, open-source two-way sync tool between GitHub issues/PRs and Jira tasks
Built with TypeScript, featuring smart mapping logic, resilient background workers, and an API-first architecture.
Features β’ Quick Start β’ Documentation β’ Contributing
β Star on GitHub β’ π Documentation β’ π Quick Start β’ π¬ Discussions
- Two-way Sync: Automatic bidirectional synchronization between GitHub and Jira
- Smart Mapping: Configurable mappings for labels, statuses, users, and custom fields
- Webhook + Queue Architecture: Reliable event processing with BullMQ and Redis
- Conflict Resolution: Configurable sync priority (GitHub-first, Jira-first, or timestamp-based)
- Deduplication: Prevents infinite sync loops and duplicate updates
- Resilient Workers: Background job processing with retry logic and error handling
- Type-Safe: Full TypeScript support with Zod schema validation
- Production Ready: Docker support, deployment configs for Railway, Fly.io, and Render
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β GitHub ββββββββββΆβ Webhooks ββββββββββΆβ Queue β
β Webhooks β β Handler β β (BullMQ) β
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β
βββββββββββββββ ββββββββββββββββ β
β Jira ββββββββββΆβ Webhooks β β
β Webhooks β β Handler β β
βββββββββββββββ ββββββββββββββββ β
βΌ
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
β PostgreSQL βββββββββββ Sync Serviceβββββββββββ Worker β
β (Mappings) β β (Logic) β β (Process) β
βββββββββββββββ ββββββββββββββββ βββββββββββββββ
- Node.js 20+
- PostgreSQL 15+
- Redis 7+
- GitHub Personal Access Token or GitHub App
- Jira API Token
# Clone the repository
git clone <your-repo-url>
cd github-jira-sync
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env
# Edit .env with your credentials
# Set up database
npm run db:generate
npm run db:migrate- Create a sync configuration:
npm run sync:init
# This creates a sync-config.yaml file- Edit the configuration file with your mappings:
name: my-sync
github:
owner: your-org
repo: your-repo
jira:
projectKey: PROJ
mappings:
status:
"To Do": "todo"
"In Progress": "in_progress"
"Done": "done"- Load the configuration via API:
curl -X POST http://localhost:3000/config \
-H "Content-Type: application/json" \
-d @sync-config.yaml# Start services with Docker Compose
docker-compose up -d
# Start the API server
npm run dev
# In another terminal, start the worker
npm run worker# Run unit tests
npm test
# Test a sync manually
npm run sync:test -- \
--config sync-config.yaml \
--github-owner your-org \
--github-repo your-repo \
--github-issue 123 \
--direction github_to_jiraPOST /webhook/github- Receive GitHub webhooksPOST /webhook/jira- Receive Jira webhooks
GET /config- List all sync configurationsGET /config/:id- Get a specific configurationPOST /config- Create a new configurationPUT /config/:id- Update a configurationDELETE /config/:id- Delete a configuration
POST /sync/test- Test a sync manuallyGET /sync/status/:resourceId- Get sync status (format:owner/repo/123)
# Initialize a new sync configuration
npm run sync:init
# Test a sync configuration
npm run sync:test -- --config config.yaml --github-issue 123
# Run the worker
npm run sync:run-worker# Server
PORT=3000
NODE_ENV=development
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/github_jira_sync
# Redis
REDIS_URL=redis://localhost:6379
# GitHub
GITHUB_OAUTH_TOKEN=ghp_...
GITHUB_WEBHOOK_SECRET=your-webhook-secret
# Jira
JIRA_BASE_URL=https://your-domain.atlassian.net
JIRA_EMAIL=[email protected]
JIRA_API_TOKEN=your-api-token
JIRA_WEBHOOK_SECRET=your-webhook-secret
# Sync
SYNC_PRIORITY=timestamp # github_first, jira_first, or timestamp{
name: string;
github: {
owner: string;
repo: string;
};
jira: {
projectKey: string;
};
mappings: {
status: Record<string, string>; // GitHub label β Jira status
users?: Record<string, string>; // GitHub username β Jira account ID
fields?: Record<string, string>; // Custom field mappings
ignoreStatuses?: string[];
ignoreLabels?: string[];
};
syncPriority: 'github_first' | 'jira_first' | 'timestamp';
syncComments: boolean;
syncLabels: boolean;
syncAssignees: boolean;
}docker build -t github-jira-sync .
docker run -p 3000:3000 --env-file .env github-jira-sync- Connect your repository to Railway
- Railway will automatically detect
railway.json - Set environment variables in Railway dashboard
- Deploy!
fly launch
# Follow the prompts, Fly.io will use fly.toml- Create a new Web Service
- Connect your repository
- Render will use
render.yamlfor configuration - Set environment variables in the dashboard
# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Generate coverage report
npm run test:coverage- Webhook Received: GitHub or Jira sends a webhook to the API
- Event Validation: Webhook signature is verified
- Job Creation: A sync job is added to the queue with deduplication
- Worker Processing: Background worker picks up the job
- Sync Execution:
- Acquires lock to prevent concurrent syncs
- Checks conflict resolution rules
- Performs the sync operation
- Updates mapping in database
- Releases lock
- Result Logging: Success or failure is logged
The sync service supports three conflict resolution strategies:
github_first: GitHub changes always take precedencejira_first: Jira changes always take precedencetimestamp: The most recent update wins (default)
- Jobs are deduplicated by a unique ID based on direction, event type, and resource
- Locks prevent concurrent syncs on the same resource
- Event IDs are stored to prevent reprocessing
- Webhook signature verification for GitHub and Jira
- Environment variable-based secrets management
- Database connection pooling
- Rate limiting on API endpoints (via BullMQ)
- Input validation with Zod schemas
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - see LICENSE file for details
Inspired by:
- Octosync - Simple GitHub-Jira sync
- Unito - Enterprise sync platform
- Exalate - Powerful integration tool
Issue: Webhooks not being received
- Check webhook URL is accessible
- Verify webhook secret matches
- Check logs for signature verification errors
Issue: Sync loops
- Ensure
ignoreStatusesandignoreLabelsare configured - Check sync priority settings
- Verify lock mechanism is working
Issue: Jobs stuck in queue
- Check Redis connection
- Verify worker is running
- Check for error logs
Built with β€οΈ using TypeScript, Fastify, BullMQ, and Prisma