Hi everyone,
I recently worked on a problem where we needed to migrate attachments across Jira instances.
Most available approaches depend on:
- Jira admins with elevated access
- External tools or paid plugins
I wanted to explore if this could be solved using only Jira’s REST APIs.
So I built a Java-based solution that:
- Migrates attachments from source to target issues
- Supports bulk migration using CSV (1000+ issues)
- Handles multiple attachments per issue
- Streams files directly without storing them locally
During implementation, I faced a few challenges:
- 403 authentication issues
- 303 redirect handling while downloading attachments
- Designing a streaming approach using InputStream / OutputStream
This helped me understand Jira beyond UI capabilities and approach it from an engineering perspective.
I’m curious to know:
Has anyone tried a similar approach for attachment migration?
Are there any best practices or limitations I should be aware of?
Happy to share more details if needed.
Hi @Aruna Ramesh kumar ,
I can share two different approaches we used for different use cases:
All in all, there's no ideal out-of-the-box solution, so some form of customization is needed. ⚙️
Cheers,
Tobi
Forge app are probably the closest option to a native solution.
This is one of those areas where I keep saying: it’s great to see AI solutions being added, but it would also be good to close at least some of the gaps where Data Center still has capabilities that Cloud is missing, and to take care of some basic use cases like this as well.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Tomislav Tobijas , thanks for sharing these approaches — really helpful breakdown!
I explored a similar custom script-based approach for cross-instance migration, especially for one-time or controlled bulk use cases. In my scenario, attachments weren’t directly accessible externally, so I used Jira REST APIs to fetch and stream them securely from the source instance and upload to the target.
I agree with your point — there’s no ideal out-of-the-box solution yet, and some level of customization is almost always needed depending on the use case.
Forge definitely looks like the closest native approach for ongoing synchronization. But for bulk migrations, I found script-based solutions to be simpler and more flexible to control.
Sharing my implementation here in case it’s useful:
👉 [GitHub - arunaramesh133-lang/jira-cross-instance-attachment-migrator: Migrate Jira attachments acro…]
Would be interested to hear your thoughts on handling large-scale migrations or any best practices you’ve seen in production scenarios.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello @Aruna Ramesh kumar
Nice work building this, the streaming approach is the right call for bulk migrations, avoids disk I/O issues and keeps memory usage predictable.
A couple of things worth watching out for at scale:
The `X-Atlassian-Token: no-check` header is required when POSTing attachments to the target instance. Without it you'll get a 403 even with valid credentials, it's easy to miss since it's not always obvious from the error.
At 1000+ issues, API rate limiting on the target instance can become a real bottleneck. Worth building in retry logic with exponential backoff if you haven't already.
Also worth checking the attachment size limit on the target instance upfront. If the target has a lower limit than the source, those uploads will fail silently unless you're explicitly handling the response codes.
Would love to see the code if you're planning to share it, this kind of solution comes up regularly and would be useful for the community.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Arkadiusz Wroblewski , thanks a lot for the feedback — really appreciate it!
You're absolutely right about the X-Atlassian-Token: no-check header. I initially ran into 403 errors during upload and later realized this header is required when POSTing attachments. I've now incorporated it into the upload logic.
I also agree on the rate limiting concern. For larger datasets (1000+ issues), I’ve started adding retry logic with basic backoff handling, and I’m planning to improve it further with exponential backoff and better throttling.
Regarding attachment size limits, that’s a great point. I’m now validating responses more explicitly to catch such failures instead of assuming successful uploads.
As suggested, I’ve made the solution available here:
👉 [GitHub - arunaramesh133-lang/jira-cross-instance-attachment-migrator: Migrate Jira attachments acro…]
It supports:
Would love any further suggestions or improvements from the community!
Thanks again for your valuable inputs 🙌
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Just to add a quick clarification - this approach doesn’t require admin-level access.
It works with standard user permissions, as long as the user has:
- Access to view source issues and attachments
- Permission to add attachments in the target project
So it can be executed using a regular API token with appropriate project-level permissions.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
(duplicate — removing)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi all, thanks for sharing these approaches — very insightful!
I explored a similar custom script-based approach, especially for cases where a lightweight, controllable solution is needed without relying on Forge or plugins.
In my case, I built a Java-based solution using Jira REST APIs that:
One of the key challenges I faced was handling authentication nuances (like X-Atlassian-Token) and download redirects, but it worked reliably once addressed.
I agree that Forge is probably the closest native option, but for one-time migrations or controlled bulk operations, a script-based approach can be simpler and more flexible.
Sharing the implementation here in case it helps others:
👉 GitHub - arunaramesh133-lang/jira-cross-instance-attachment-migrator: Migrate Jira attachments acro…
Would be great to hear thoughts or suggestions!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
When I needed to migrate attachments, I just used a CSV import : How to migrate issues with attachments using the CSV import in Jira Server and Data Center | Jira and Jira Service Management | Atlassian Support
I can confirm that it's working fine for Jira Cloud too. You just need to be sure that the url of the attachments is reachable by your target instance.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Mohamed Benziane , thanks for sharing this approach!
Yes, CSV import with attachment URLs works well when the attachments are already accessible via public or reachable URLs.
In my case, the challenge was slightly different — the attachments were stored within a source Jira instance and not directly accessible externally. So I explored a REST API-based approach to:
This helped in scenarios where:
So I see both approaches as useful depending on the use case 👍
I’ve shared the implementation here in case it helps:
👉 [GitHub - arunaramesh133-lang/jira-cross-instance-attachment-migrator: Migrate Jira attachments acro…]
Would be interested to hear if you’ve handled similar restricted-access scenarios!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.