Connect to Forge migration, or how I learned to love responding to customer requests

Atlassian,

We need to talk about Connect to Forge migration. This has become more urgent because of to the recent decisions regarding notifying customers of any use of Connect modules in Forge apps.

The thing is… in order to migrate our customer from Connect to Forge, we need to map the Forge installation to the previous Connect installation. As per recommendation by Atlassian, we used the Connect clientKey property as the unique identifier.

However, Forge does not provide us with that identifier upon installation. Forge does not have a migration lifecycle event. Forge does not care about Connect. It treats the migration as a fresh install.

We initially solved this using the connectModules lifecycle event in our manifest, as per Atlassian documentation, which allows us to capture the uninstall event which is triggered when a customer upgrades from Connect to Forge. However, adding this module to our manifest will trigger a “OH MY GOD, OH MY GOD, OH MY GOD, YOUR ENTIRE INSTANCE IS ABOUT TO BURST IN FLAMES” message to end-users.

So we went with the second option in the documentation, and instead called the API to get the connect key using the magic property.

The problem with that approach? That is documented here:

During app installation, the Atlassian account used by your app to authenticate with Atlassian APIs is granted various permissions and group memberships for the site it is being installed into. This process is eventually consistent, and the installed event may be sent before the app is granted the permissions needed to call certain APIs using .asApp(). For large sites, it may take a very long time (minutes) for your app user to be fully granted the requisite permissions.

We’re seeing situations in which the app does not yet have the required permissions to retrieve the clientKey from the API because the app is still being provisioned, even though the end-user can already interact with the app. So we can’t map the Forge installation with the Connect app, and as such cannot show them their data.

How does Atlassian want us to solve this?

Since it’s your app, the technical approach is entirely your call. Happy to share my recommendation though.

This is a one-time Connect to Forge migration. If your app can detect when it’s in progress, I’d suggest showing a brief message in your UI letting customers know a migration is underway and there may be a short period of downtime.

For context: between automatic migrations and the extended timeline we’ve provided, most apps’ install bases have already moved to Forge. That means only a limited number of installs would still see any migration messaging. I haven’t checked the specifics for your apps yet, so your situation may differ.

On your choice of approach: going with the second option from the documentation is the right call. The first option uses a Connect module, which is why the warning banner appears, and it would also trigger the updated revenue share: Updates to Marketplace Revenue Share: 2026 - Inside Atlassian

Well… sure, but I’m limited to the options provided by Atlassian.

Ok, but that was not the subject of this topic?

But… that doesn’t answer the fact that there are technical issues with the second option?

This whole thread is about the fact that Atlassian infrastructure decisions limit my ability to migrate and these answers are not addressing that.

  • Why is Atlassian not providing the clientKey in the Forge FIT or lifecycle payloads?
  • How am I supposed to call an API when the app permissions are not yet provided?

Those are the questions that are relevant to this thread, and both questions are directed at Atlassian. I know what I can do for the migrations, but I’m stuck because of something Atlassian should be doing.

clientKey is specific to Connect and isn’t included in Forge payloads by design.

This is a known timing issue — permissions may not be fully propagated immediately after installation. The recommended approach is to implement a backoff-retry pattern, which is covered in the Forge’s retry handling. Would that work for your use case?

What I’m looking for is a solution to the fact that I need to know upon app installation that the customer is replacing the Connect app with a Forge app.

If I want to show a UI message that migration is pending, if I want to start migrating data, if I want to start any action involving the transition from Connect to Forge, I need to know that this is a migration action and not a fresh Forge install.

Right now, there is no way for me to know.

The only solution that Marketplace Partners have come up with is to retroactively retrieve the instance cloud ID and store it with existing Connect apps as an additional identifier as this is the only way to synchronously match transitions from Connect to Forge.

Obviously, but from a partner perspective, that was an incorrect design choice.

Is it really that strange to ask from Atlassian to tell us that a customer is migrating from Connect to Forge in a synchronous way?

You could persist a installationComplete flag for the installationId, initialised to false and tested by the UI. Set to true when your installation trigger runs to completion, including the clientKey from the App Properties API and any associated Connect-to-Forge migrations.

Or, hear me out, if the avi:forge:upgraded:app was reliably and timely sent and included info about the previous and current version, we could use that without having to implement weird workarounds that nobody will remember in 6 months and might eventually break due to unrelated changes.

…or the clientKey could be included in at least the avi:forge:upgraded:app event.

The problem with this solution is that it basically forces me to run the same event in a loop waiting for Atlassian to finish for every installation, regardless of whether this is an upgrade or not. Because I cannot distinguish between a fresh Forge installation and a Connect to Forge upgrade.

The only way to determine this, is to wait for API access, query the app properties API and fetch the clientKey. If we do not have a database record for that client key, we must assume that this is a fresh Forge install

Please note that the app properties API will return a clientKey, even if there was no Connect installation

This is a lot of code & assumptions for a simple yes/no answer for which Atlassian already has the answer when it upgrades the app from Connect to Forge

Given that Atlassian has stopped responding, I think it is safe to assume that:

  1. Atlassian prefers for hundreds of app vendors to implement a polling mechanism to check if Forge is done provisioning for each installation, for thousands of apps and ten-thousands of installs, even though Atlassian knows when an install has finished (it was implemented in Connect, with the Install vs Enabled lifecycle events)

  2. Atlassian considers some ideological design decision to be more important than providing customers a smooth transition from Forge to Connect

I guess sometimes inaction is also action.