RFC 119: Forge preUninstall Module

RFCs are a way for Atlassian to share what we’re working on with our valued developer community.

It’s a document for building shared understanding of a topic. It expresses a technical solution, but can also communicate how it should be built or even document standards. The most important aspect of an RFC is that a written specification facilitates feedback and drives consensus. It is not a tool for approving or committing to ideas, but more so a collaborative practice to shape an idea and to find serious flaws early.

Please respect our community guidelines: keep it welcoming and safe by commenting on the idea not the people (especially the author); keep it tidy by keeping on topic; empower the community by keeping comments constructive. Thanks!

Project Summary

This RFC proposes introducing a pre-uninstall module for Forge apps to enable developers to perform necessary actions, such as data cleanup, before an app is uninstalled.

Publish: 13 November 2025

Discuss: 20 November 2025

Resolve: 28 November 2025

Problem

Currently, when an app is uninstalled in Connect, Atlassian sends an HTTP POST request to the app’s callback URL with an uninstalled event. This allows developers to handle use cases such as cleaning up data (e.g. removing entity properties) or taking actions to re-engage customers after uninstallation.

Forge apps migrating from Connect lack a similar uninstall callback mechanism. Once a Forge app is uninstalled, it cannot be discovered anymore and hence there is no mechanism to notify developers or trigger cleanup actions. This gap prevents developers from performing essential pre- or post-uninstallation tasks and impacts their ability to manage this part of an app’s lifecycle effectively.

Proposed Solution

We are proposing a preUninstall module developers can add to their Forge apps. It will allow for cleanup operations such as deleting Forge storage or remove secrets before an app is uninstalled.

This will work for uninstalls via CLI or Connected Apps.

An example of how a preUninstall module might look like in your manifest.yml:

# manifest.yml

modules:
  preUninstall:
    - key: cleanup-before-uninstall
      function: cleanupHandler

  functions:
    - key: cleanupHandler
      handler: index.cleanup

The functions section defines the handler that contains your cleanup logic such as deleting Forge Storage or similar.

This structure is consistent with how other Forge triggers (like scheduled or event triggers) are defined in the manifest and provides developers with an opportunity to perform necessary actions before the app is fully uninstalled.

How it works:

  • When an admin initiates an uninstall action via the UI or CLI, developers will be notified by a pre-uninstall trigger.

  • The cleanup processes can start.

  • The uninstallation process will pause for approximately 60secs, to wait for any invocation to complete. Cleanup operations should conclude in that time interval, as once the uninstallation completes, product API calls may not work.

  • The uninstallation process will proceed regardless of any failure in the function invocation. Apps should use logging or metrics for visibility on cleanup results or failures.

There won’t be any significant change expected from a user experience perspective apart from a potentially slightly longer uninstall process when cleanup actions are performed.

We are aiming to make the module available by the end of CY25.

Asks

We are keen to hear from you:

  • Would this pre-uninstall module align with your expectation regarding an app uninstallation event handling in Forge?

  • Are there additional requirements we should consider?

  • Are there any concerns about timing, reliability, or security with this approach?

3 Likes

Hi @JuliaDaehne ,

Thank you for this RFC, as this is definitely a feature that we’ve been waiting for in terms of Connect/Forge parity.

With regard to your asks:

  • Would this pre-uninstall module align with your expectation regarding an app uninstallation event handling in Forge?

Not really, because it does not support Forge Remote. There will be plenty of apps that will still require remote compute/storage and will be utilising Forge Remote. The current solution only supports a Forge native event handler, and limits the uninstall window to 60 seconds. This is a very limited implementation that will probably not work for more complex apps that require a lot more clean-up.

  • Are there additional requirements we should consider?

Yes, the requirement of supporting apps that utilise Forge Remote

  • Are there any concerns about timing, reliability, or security with this approach?

Yes, the problem with this approach is that it has a hard time limit. Given that there might be a requirement to also clean remote resources, and with the fact that the event handler might run into performance issues with Forge infrastructure when trying to clean data, the 60s window is really limited.

Would it be possible to implement a callback mechanism that allows the app to indicate clean up succeeded or failed, with a more realistic timeout (10-30 minutes?), a retry mechanism for end users and a force delete?

I understand that the deletion of the app is probably also coupled with the subscription / billing and other Atlassian processes, but it would be great if this can be decoupled and that there will be more room for Marketplace Partners to make sure there is a proper cleanup.

10 Likes

Thanks for sharing this!

One problem with the Connect uninstall event was that we couldn’t rely on it being sent for cases where for example a complete site was deleted / deactivated etc. So we ended up with complicated workarounds for cleaning up data such as left-over Connect tenant records.

Is this new module guaranteed to be invoked for such cases where we didn’t receive the Connect event in the past?

Also just out of curiosity: why is this not just a standard event sent to a trigger module?

We’d also like to see Forge Remote support.

10 Likes

Thanks, this sounds really useful!

We also need Forge Remote support here.

We would be unable to complete all cleanup work within 60 seconds, but we could schedule the cleanup work during that time and the actual cleanup would take up to 90 days (like it does currently in Connect).

3 Likes

Another +1 for Forge remote, required for connect parity.

Forge storage tied to the installation should be purged regardless of this module being implemented. (But, for Forge apps not using remote, I appreciate that this can allow us to clean-up Forge storage instantly)

For Runs on Atlassian apps, customers can reach out to Atlassian support after an uninstall/re-install and provide the installation IDs to re-link Forge storage data for that cloudId (If this is still supported?).

  • What does this mean in terms of non-remote apps that implement this module?

  • Would the uninstalled data invoked from this module be able to be recovered?

    • If so, how does the data persist + how to you differentiate a Forge secret deletion manually invoked via the UI, compared to data deleted from this module?

As others have mentioned, Including this as modules.trigger.events as an avi:forge:preUninstall:app would be better to support forge remote (and get closer to Connect uninstall lifecycle parity).

Whilst the hook can be sent to confirm the request for data deletion, if the remote does not complete deletion, the uninstall invocation may fail. Having an approach to accept a preUninstall lifecycle, then respond once data has been cleaned would be best.

5 Likes

+1 for Forge Remote support.

This is a great improvement, as it not only is a great feature itself, but it is also a missing feature from a parity perspective with Connect.

2 Likes

Second this - it’s great that uninstall events are being added, but maybe to quicker support Forge remote as well, having this analog to “avi:forge:installed:app” might make sense!

2 Likes

Hi @JuliaDaehne ,

Thanks for the RFC!

Would this pre-uninstall module align with your expectation regarding an app uninstallation event handling in Forge?

I would have expected this to be just a normal trigger/event like other lifecycle events that already exist. Is there any reasoning why you’d put this into its own module?

Are there additional requirements we should consider?

If we were to do cleanup well, we’d need time. A lot more than the 25s per invocation we get or the up to 900s we’d get if this somehow were a scheduled trigger invocation. Let me give you an example: In the past we had a Forge app that added JQL keywords via Entity Properties. When installing the app, we’d have to touch every work item to set our properties, so the keywords could be used in JQL searches. When uninstalling such an app, I believe we should clean up those properties. In other cases, vendors might use entity properties to store some meta data on a work item or a page. Those should also be cleaned up if possible, but that can take a long time.

Are there any concerns about timing, reliability, or security with this approach?

Depending on the app, we won’t be able to do a meaningful cleanup in a 60 second window.

Additionally, I have the following notes:

  • Forge logs disappear after an uninstall, which will make it extremely hard to debug any cleanup issue in production.
  • Bulk actions for typical cleanup tasks might be really useful. E.g. deleting KVS entries, deleting a property from all work items/spaces/content, etc.
  • Ideally, we’d be able to use the queue to schedule cleanup tasks for a longer time frames.

All in all, it would be really great to have a way to perform a cleanup when uninstalling so thank you for tackling this!

2 Likes

Thanks for this RFC.

This would be necessary to achieve feature parity with Connect. I’d also like to reiterate a couple of crucial points mentioned by others here:

  • It is vital to be able to use Forge Remote with this feature.
  • Following from the above, implementing this as a Trigger event avi:forge:preUninstall:app (maybe with some better naming) would then also be much more aligned with all the other events, like avi:forge:installed:app.

I appreciate that this is under consideration, and hope for a swift implementation of a version of it.

1 Like

I think this is a crucial aspect: what happens to (deleted) vendor data after a re-link?

6 Likes

Hey @jbevan would you be able to make us understand what clean up operations you are running? It would be interesting to understand your use case better

Thanks for this quick feedback round! That’s very helpful.

  • Confirming the preuninstall module will work for remotes as well. We can add a manifest example to reflect the emote use case as well if this is helpful
  • Customers can request data recovery after an app has been uninstall for up to 30 days after the uninstall has occurred. Cleaned up data however will not be recoverable

@EdijsVilci keen to understand why a trigger event is preferred?

The reason we chose the proposed solution is that once an app is uninstalled it cannot be discovered anymore and we therefore cannot send an uninstall event.

@JuliaDaehne

The reason we chose the proposed solution is that once an app is uninstalled it cannot be discovered anymore and we therefore cannot send an uninstall event.

A trigger event would be more in line with other product events. In this case, it signals that “the user has triggered the app uninstallation process“, and we can go off of this to do whatever needs to be done.

A module implementation implies some specific configuration options (like defaults for some automated Forge-native cleanup, maybe?) that a triggered event doesn’t have. Otherwise, this module then effectively acts like a trigger event, or am I getting it wrong? There are probably some implementation details I am not aware of from a Forge infrastructure perspective, but from my end, it seems like a plain trigger event, so I agreed with others that it could be just an event.

It is good to hear that Forge Remote will be supported. Please do provide examples of how this would look in the manifest.

1 Like

Hi Julia,

I am glad to hear about support for Forge Remotes.

In terms of the “trigger vs module implementation”, I imagine that this is being suggested as a module because Atlassian believes that the pre-uninstall module will execute synchronously and be on the critical path for the uninstall?

Can Atlassian also think about how this could be built in an asynchronous context? Other partners have already mentioned that substantial work is sometimes required during uninstall events. Some of that work may still require access to the host instance.

Could apps elect to tell the platform that they need up to ‘X’ minutes/hours to perform uninstall work? Could there be such a concept as a “deferred uninstall”, wherein the majority of the modules of an app (UI components, pages, triggers) are silenced as soon as the admin clicks the “uninstall” button, but the app’s back end retains OAuth access to the instance during the elected uninstall interval? I imagine that this interval would default to zero, but that it could be extended based on the app vendor’s needs.

If this were made asynchronous, then could it possibly also allow Atlassian to use a simple trigger for the pre-uninstall event rather than a separate module type?

2 Likes

We delete some database entries and some “files” in object storage within our hosting infrastructure.
Occasionally the database entries can take hours to delete so we use DynamoDB’s built-in item expiry mechanism.
To avoid problems with customers uninstalling and reinstalling in a short space of time (a few days) and losing their data we commit to retaining customer data for a few months after uninstall “just in case”.

1 Like

Would app vendors be billed for the compute cost of running cleanup operations?

Hi @JuliaDaehne ,

What would recovery do after a clean up of data? And is there a notification for vendors or apps? I fail to understand this feature.

However on a meta level, how many levels of clean up and uninstall and recovery will be possible?

1 Like

@JuliaDaehne Thanks for the RFC. It would be helpful to share a bit more context on why and not just the what. It doesn’t seem reasonable to expect the clean up to finish in 60 seconds, so sharing why this is important and part of the suggestion would be very helpful.

Is there a customer expectation that apps can’t have their own data retention policies, and all data must be immediately cleaned up?

Today, for Connect apps, we retain the customer data for 30 days after uninstallation. We have quite a lot of configuration data and we don’t want to end up in a situation where customer has uninstalled the app (sometimes accidentally), and would have to reconfigure everything. Customers sometimes uninstall apps as it has been a troubleshooting step on-prem. Nuking all of the the data without an option to recover within a reasonable time sounds like problems to me.

Same as @marc pointed out, I am not sure I understand what this would look like. Can you elaborate on this, what would be recovered?

1 Like

Hi all,

To provide some more context on why we’ve specifically avoided the use of an “event”:

  • Product API access is removed once the app is uninstalled
    • Once we uninstall an app from a product workspace (eg. Confluence or Jira), the app will lose permission to perform product API calls (as we delete grants as part of the uninstallation process). Therefore, making this an asynchronous event would be somewhat misleading, as the app will have limited access once the uninstallation process completes.
  • App pre-uninstall actions must be non-blocking
    • The invocation of this uninstall hook MUST be non-blocking (and time-bound), as Forge app uninstallations run as part of other important Atlassian business processes and we cannot block or hinder those processes.

Conceptually, an “event” generally denotes something that has already happened. We’ve specifically chosen to call this “pre-uninstall”, to indicate that this is triggered before the uninstallation occurs.

Thanks,

Josh.

1 Like