Atlassian Migrations — The App Problem Nobody Warned You About
Mihai Perdum
Author
10 min readApril 1, 2026
In my last post, I said something that apparently struck a nerve: waiting for perfection is the single most expensive mistake an organization can make. I stand by that. But I realized I left something on the table — the specific, grinding, soul-crushing dimension of migrations where that truth hits the hardest.
Apps.
Not the core platform. Not the data. Not the users, the permissions, the workflows — though those are all their own special brand of painful. I'm talking about the Marketplace apps. The ones your client installed six years ago, configured with surgical precision over hundreds of hours, and now treats as load-bearing walls in their operational architecture. The ones where the vendor's Cloud version exists, technically, but is a fundamentally different product wearing the same name.
This is the story of one such migration. It's real. And if you've been in this space long enough, some version of it has probably happened to you.
The Setup: When Your Client Loves Email
The client had a mature Data Center environment. Jira Software, Jira Service Management, Confluence — the usual stack. Thousands of users. Hundreds of projects. And an email integration setup so elaborate it made my eye twitch the first time I saw it.
They were running two apps that, together, formed the backbone of their external communication: JEMH (Jira Enterprise Mail Handler) for inbound email processing, and Email This Issue (ETI) for outbound notifications. Both from different vendors. Both deeply configured. Both — and this is the part that matters — operating in ways that don't translate cleanly to Cloud.
In Data Center, JEMH was doing heavy lifting. Conditional routing based on email headers. Custom HTML notification templates with Velocity logic that branched on issue type, project, priority, custom field values. Regex-based project matching. Blacklists. Reporter overrides. The kind of configuration that takes a senior admin months to build and that nobody else in the organization fully understands.
ETI, on the other side, handled outgoing email with equally intricate templates. Conditional blocks inside Velocity markup. Nested templates rendering within templates. JQL queries embedded inside email bodies. The DC version gave you full access to Jira's Java internals — , , — which meant the templates were, in practice, small programs disguised as HTML.
Beautiful, terrifying, and completely non-portable.
The Cloud Reality: Same Name, Different Universe
Here's what the Marketplace listings don't make obvious at first glance: JEMH Cloud (JEMHC) and the DC version share a name and a vendor. That's roughly where the similarities end.
The Plugin People — JEMH's vendor — have been transparent about this, and I give them credit for that. Their migration documentation states it plainly: there is no automated migration tool from DC to Cloud. The data structures are different. The event model is different. The scripting capabilities are different. You're rebuilding from scratch.
Let me be specific about what "from scratch" means here. In DC, JEMH's event model gives you the full richness of Jira's internal event system — dozens of distinct event types, each triggerable independently. In Cloud, JEMHC works through webhooks and only receives three event types: Created, Updated, and Deleted. That's it. Your finely tuned notification logic that distinguished between a priority change, an assignee change, a status transition, and a comment addition? Gone. Collapsed into "Updated."
DC's JEMH lets you script with full access to Jira's APIs — JQL queries, remote calls, deep field inspection. Cloud's JEMHC gives you JavaScript with access to the issue JSON and mail content. No JQL. No Jira API. No remote calls. The scripting capability went from a Swiss Army knife to a butter knife.
And the templates? DC templates are native Jira Velocity templates using IssueEvent and TemplateIssue objects — the same engine that powers Jira's own notification system. Cloud templates are reimplemented "Themes" built on webhook payloads. They support Velocity syntax, including conditionals, but the context objects are completely different. You cannot copy a DC template into Cloud and expect it to work. You cannot even use the same mental model.
ETI tells a similar story, though with one critical difference: it actually has an automated migration tool. That sounds better than it is. The tool migrates configuration, but workflow post-function settings don't transfer at all. The default event type doesn't migrate. Email templates carry over structurally, but every variable needs reconfiguration because — and this is a direct quote from the vendor's documentation — "variables in the Cloud version work from a technical point of view, in a different way than in the DC version." The regex syntax is different. The outgoing mail connection can't use Jira's built-in SMTP anymore; you need to configure your own OAuth2 flow.
So you're not migrating. You're rebuilding. For both apps. Simultaneously. On a deadline.
The Call That Changed Nothing
We did what any responsible consultant does in this situation: we got on a call with the vendor.
This is where the story gets interesting — and where the real lesson lives. The vendor was helpful. Genuinely helpful. They walked us through the Cloud architecture, the template system, the known limitations. They acknowledged the gaps. They weren't evasive. They weren't dismissive. They were honest.
And then we asked the question: How do we replicate the conditional HTML template logic from DC?
In DC, our client had a single email template that used conditional Velocity blocks to render completely different HTML layouts depending on the issue type, project category, and priority level. One template. Multiple outputs. It was elegant. It was efficient. It was the kind of thing a senior admin builds once and the organization relies on for years.
In Cloud, that conditional approach — at least in the way it was implemented in DC — doesn't have a direct equivalent with the same depth of context. The vendor suggested an approach. They hinted at features that might be coming. They mentioned possibilities. They left us with anticipation.
Anticipation is a dangerous thing in a migration.
Because here's what anticipation means in practice: it means waiting. It means telling the client "the vendor might have a better solution soon." It means the client hears "soon" and interprets it as "next week." It means the deadline doesn't move, the vendor's roadmap isn't committed, and you — the consultant — are stuck in the gap between what the client needs now and what the vendor might deliver eventually.
The Real Question: Can You Afford to Wait?
This is the moment every migration consultant faces, and it's the moment that separates the projects that succeed from the ones that rot.
The instinct — the correct instinct, in an ideal world — is to wait for the right answer. Get the vendor's guidance. Implement it the proper way. Do it once, do it right.
But here's the uncomfortable truth: the right answer doesn't always exist yet.
The vendor isn't withholding a solution. They genuinely don't have one — or they're building one, but it's not done, and the timeline is their own. They're dealing with their own engineering constraints, their own Cloud platform limitations, their own priorities. Atlassian's Forge and Connect frameworks impose hard boundaries on what apps can do. The same operational constraints that made Atlassian kill Data Center — the impossibility of maintaining two parallel ecosystems — apply to every vendor in the Marketplace. They're building for Cloud-first too, and some of that building isn't finished.
So the slippery slope emerges. You wait for the "correct" approach. A week passes. Then two. The vendor sends a follow-up: "We're working on it, no ETA." The client sends a different kind of follow-up: "Where are we on this? The deadline is in six weeks." Your project manager updates the risk register. The line item turns amber. Then red.
I've seen this pattern before. Not just with JEMH and ETI — across the entire Marketplace ecosystem.
This Isn't Isolated. This Is the Pattern.
E7 Solutions — an Atlassian Solution Partner — documented a migration where Jira Workflow Toolbox could only carry over roughly a third of its DC functionality to Cloud. A third. The rest had to be rebuilt, replaced, or abandoned. ScriptRunner Behaviors — a feature used extensively in enterprise DC environments — simply don't exist in Cloud. They don't migrate. They don't have an equivalent. They're gone.
Praecipio documented a 16,000-user enterprise migration where they manually recreated over a thousand ScriptRunner behaviors. One thousand. Each one a custom piece of logic that someone had written, tested, deployed, and relied on. Each one individually assessed, rewritten for Cloud's REST-based ScriptRunner, tested again, and deployed again.
And these are the success stories. These are the migrations that made it to the other side.
The Atlassian Community is full of the other kind. One enterprise admin — 5,000 Jira users, 4,000 Confluence users, 1,200 JSM users — posted a thread describing their migration experience in terms I won't paraphrase because the raw honesty matters: they called it a mess. Less functionality in Cloud, plugins that partially migrate, no clean migration path.
Research from Praecipio suggests that up to 30% of Marketplace apps may not be fully cloud-compatible. Atlassian's own guidance acknowledges that some vendors have simply chosen not to build Cloud versions — either because the business case doesn't support it or because Cloud's technical constraints make it infeasible.
These aren't edge cases. This is the landscape.
So What Do You Actually Do?
You act. That's what you do.
Not recklessly. Not without thought. But you act, because the alternative — waiting for a vendor solution that may or may not materialize, on a timeline you don't control, while your client's deadline marches forward with the indifference of a calendar — is worse than any imperfect solution you implement today.
For our JEMH and ETI situation, here's what we did: we built the Cloud configuration using the tools available right now. For the conditional templates that couldn't be replicated as a single template with branching logic, we created multiple templates — one per condition path. Is it as elegant as the DC approach? No. Does it result in more templates to maintain? Yes. Is it functional, testable, deployable, and — critically — live before the deadline? Absolutely.
And here's the key decision: we left a path for appeal.
This is the principle I want to hammer home, because it's the thing that makes the "act now" philosophy sustainable rather than reckless. When you implement a solution that you know isn't final — that you know might be superseded by a better vendor-supported approach in three months or six months — you document it. You build it modularly. You make it replaceable. You tell the client: "This is what we're deploying now. It works. It meets your requirements. And when the vendor releases [feature X], we can revisit this with minimal disruption."
The reason this works — the reason it's not just kicking the can — is that this isn't an app-to-app migration. We're not locked into a proprietary format that can't be changed later. Cloud configurations are mutable. Templates can be updated. Notification schemes can be adjusted. The work we do today isn't carved in stone; it's written in configuration. And configuration, unlike deadlines, is forgiving.
The Broader Principle: Controllable Imperfection Over Uncontrollable Perfection
Here's the mental model I've started applying to every app migration decision, and it's served me well:
The easiest road is the one you know and can control — or at least have some control over.
When you're waiting for a third party to develop something, to change something, to release something before the "correct" answer emerges — you have no control. You can't accelerate it. You can't influence it. You can't even get a reliable timeline for it. You're a passenger.
When you implement a solution using the tools available today — even if that solution is less elegant, requires more maintenance, or covers only 80% of the ideal — you're in the driver's seat. You control the timeline. You control the quality. You control the iteration cycle. And when the better solution arrives — if it arrives — you can adopt it on your terms, on your schedule, with full knowledge of what needs to change.
This philosophy applies beyond email handlers. It applies to every Marketplace app decision in a migration:
ScriptRunner behaviors don't migrate? Rebuild what you can using Cloud's Automation for Jira and REST-based ScriptRunner. Document what's missing. Revisit when the platform catches up.
Jira Workflow Toolbox only brings a third of its functionality? Identify the critical third. Implement that. The other two-thirds either get rebuilt in Cloud-native tools or get formally deprioritized with stakeholder sign-off.
A niche app has no Cloud equivalent? Find the closest alternative. Accept the feature gap. Document the delta. Move on.
The pattern is always the same: act, document, leave a path for improvement.
A Note on What Cloud Actually Gives You
It's easy to read all of this and conclude that Cloud is a downgrade. It isn't. The migration path is painful, yes. The app ecosystem has gaps, yes. But Cloud itself is a fundamentally more capable platform — and the Forge framework that constrains app vendors today is the same framework that enables entirely new categories of solutions that weren't possible in DC.
I'll give you two examples from my own work.
CogniRunner is a Forge app I built that adds AI-powered workflow validation to Jira Cloud. Describe your validation criteria in plain English — "reject this transition if the description appears to be a duplicate" or "block this if the attachment contains sensitive data" — and the AI evaluates it in real time. It can analyze attached documents, images, spreadsheets. It can run JQL searches autonomously to detect duplicates. This kind of capability — AI as a native workflow participant — simply wasn't possible in DC's architecture. Not because of vendor limitations, but because the platform didn't support it.
SentinelVault is another Forge app — this one for Confluence Cloud. It adds attachment protection and file locking, something Confluence has never had natively on any platform. Seal a file, and nobody can overwrite it while you're working on it. If someone tries, the change is automatically reverted within seconds. Real-time violation detection, multi-channel notifications, space-level administration. This solves a problem that plagued Confluence in DC just as much as it does in Cloud — but the solution is only possible because of Forge's real-time event triggers and platform-level storage.
The point isn't to sell you on these specific tools. The point is that Cloud's architecture enables solutions that DC couldn't support, and the ecosystem is building toward that future. The apps you lose in migration are real losses. But the apps you gain — and the apps that haven't been built yet — represent a trajectory that DC was never on.
The Clock Doesn't Care About Your Vendor's Roadmap
Let me close with the math, because the math is what ultimately forces the decision.
Data Center's end-of-life is March 28, 2029. Enterprise migrations take twelve to eighteen months. Assessment and planning take three to six months. That means if you want a well-executed migration, you need to be in active execution by mid-2027 — and in planning now.
New DC Marketplace app submissions ended in December 2025. New DC license sales close to new customers in March 2026. The DC Marketplace ecosystem is entering managed decline. Vendors have diminishing financial incentive to invest in DC app updates, bug fixes, or new features. The app you're waiting on to release a better DC-to-Cloud migration tool? Their engineering team is probably being reallocated to Cloud-native development, because that's where their future revenue lives.
Every week you spend waiting for a vendor to solve your migration problem is a week closer to the deadline with no guarantee the solution will arrive. Every month of parallel DC-plus-Cloud licensing eats budget that could fund post-migration optimization. Every quarter on DC is a quarter without the AI capabilities, the collaboration features, and the platform innovations that are Cloud-exclusive and accelerating.
The vendor call that leaves you with anticipation instead of answers? That's not a reason to pause. That's a signal to act.
The Bottom Line
App migrations are where Atlassian migrations go to die. Not because the apps are bad — the vendors are doing genuinely hard work under genuine platform constraints. Not because the consultants are incompetent — this is objectively difficult. But because the instinct to wait for the "correct" answer is so strong, so deeply ingrained in how we think about enterprise technology, that it overrides the pragmatic reality staring us in the face.
The correct answer is often: there is no correct answer yet. And when there's no correct answer, the next best thing is a good enough answer implemented today, documented clearly, built modularly, with a path for improvement when — if — the correct answer eventually emerges.
Build it. Ship it. Document it. Leave the door open. Move on.
Or wait. Hold and hold fast. Watch the deadline approach. Watch the vendor's roadmap slip. Watch your client's frustration compound. And explain, in six months, why the migration is behind schedule because you were waiting for someone else to make a decision that was always yours to make.
The apps are the migration. The migration is the apps. And the apps — like everything else in this ecosystem — are imperfect by necessity, not by design. Act accordingly.