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
“App Migrations - Delta Migrations for Apps” is an initiative to provide marketplace partners with the ability to support delta migrations for their apps, allowing for smaller migrations with reduced migration downtime. This will be achieved by providing marketplace partners with information regarding the difference between the initial migration and any future deltas and allowing them to decide how to use this information to reconcile the changes.
-
Publish: 26 August 2025
-
Discuss: 16 September 2025
-
Resolve: 30 September 2025
Problem
Atlassian is developing “delta” migrations, which are migrations that run after the initial migration, transferring only the data that has changed since the last migration (the “delta”). These migrations minimise customer downtime and operational pressure by replacing a single large traditional migration (often run on weekends) with multiple delta migrations that offers a wider margin for error and does not block the customer’s server.
However, apps currently lack visibility into data changes between migrations, requiring every app migration to re-migrate all the app’s data during subsequent migrations. Because app migrations must currently be rerun in full, they will not be fully capable of participating in delta migrations.
We have an opportunity to give apps the capacity to fully participate in delta migrations by offering them visibility into data deltas so that they can identify mutations and reconcile the differences with the cloud site. This offers customers less down-time than the traditional migration flow.
Who are we solving for:
For marketplace partners:
-
Allow marketplace partners to choose between a single, large-scale traditional migration, or a set of smaller less-error-prone migrations, based off of deltas from an initial migration. This will:
-
Reduce load on their infrastructure when larger customers migrate
-
Reduce the chances of an error occurring during a migration, thereby reducing the “blast radius” of the error to only the delta migration rather than the whole migration. Meaning that only the delta would need to be rerun rather than the entire migration.
-
For customers:
-
Offer customers less down-time than the traditional migration flow.
-
Give customers the option for smaller delta migrations with a lower chance of failure
Proposed Solution
Atlassian will provide an updated listener interface for marketplace partners to integrate with, enabling the transmission of a list of modified containers (projects or spaces), and other information since the last delta migration to the cloud site. Marketplace partners can receive these events by utilising the new migrations listeners.
In Your Server App:
Your server app must implement the new listener methods to support delta migrations. Below are the DiscoverableListener interface changes, which would be similar to the changes for the multi-transfer and forge listeners. The new methods are default, so implementation is optional. By default, your app does not support delta migrations.
interface DiscoverableListener {
// NEW Connect listener methods
/**
* Decides whether delta migration is supported for migration
* (e.g. for this customer)
*/
default boolean isDeltaMigrationSupported(DeltaMigrationDetailsV1 migrationDetails) {
return false;
}
/**
* Perform the delta migration. This functions the same way as
* `onStartAppMigration()`, but apps will only migrate the app data that is new
* or changed.
*/
default void onStartDeltaMigration(
DeltaAppCloudForgeMigrationGateway gateway,
String transferId,
DeltaMigrationDetailsV1 migrationDetails
) {
}
// EXISTING Connect listener methods
void onStartAppMigration(
AppCloudMigrationGateway gateway,
String transferId,
MigrationDetailsV1 migrationDetails
);
...
}
// New classes/interfaces used in the above listener definition:
interface DeltaAppCloudMigrationGateway extends AppCloudMigrationGateway {
/** Get core data containers (ContainerV1) that have changed since last delta migration. */
PaginatedContainers getPaginatedDeltaContainers(String transferId, ContainerType containerType, int pageSize);
}
class DeltaMigrationDetailsV1 extends MigrationDetailsV1 {
public Instant getLastDeltaMigrationTimestamp();
}
The changes are as follows:
-
boolean isDeltaMigrationSupported(): Atlassian uses this to determine if your app supports delta migrations.
-
void onStartDeltaMigration(): This method is called instead of onStartAppMigration() if your app supports delta migrations. Your app will only migrate new or changed app data. The method passes the following parameters:
-
DeltaMigrationDetailsV1: Use this to retrieve the last delta migration run time via getLastDeltaMigrationTimestamp().
-
DeltaAppCloudMigrationGateway: Use this to obtain core data containers (ContainerV1) that have changed since the last delta migration (e.g., projects with modified issues). The logic with which we calculate which containers to send are detailed in https://community.developer.atlassian.com/t/rfc-111-delta-migrations-for-apps/94792#p-209716-change-detection-10.
-
Atlassian does not have visibility into each app’s data structures. The intention is that by providing the last delta timestamp and the list of core containers changed since the last migration apps should be able calculate to the delta successfully.
Whether this information is sufficient or not is something we would like your input on.
In your cloud app:
Cloud apps will receive notifications on delta app migration events for each transfers via,
-
Forge migration events for Forge applications.
-
Webhooks and events for Connect applications.
Events for delta migrations will include two additional fields in the event payload:
-
lastDeltaMigrationTimestamp: timestamp of the start of the last delta migration.
-
deltaMigrationTimestamp: timestamp of the start of the current migration as follows.
For Forge apps:
Forge apps can utilise existing Forge app migrations APIs with respective transfer IDs of each transfer.
Sample Forge Event Payload:
{
"eventType": "avi:ecosystem.migration:uploaded:app_data",
"transferId": "6c01ac6f-c512-4ef7-8b48-25c1803fe305",
"lastDeltaMigrationTimestamp": "2025-08-18T15:30:04Z",
"deltaMigrationTimestamp": "2025-08-21T01:57:32Z",
"migrationDetails": {
"migrationId": "403c4f71-a0d1-4a63-97a8-487d18691c46",
"migrationScopeId": "0ba07dd9-3804-4600-9102-fa6e1efeab08",
"createdAt": 1723111376499,
"cloudUrl": "https://your-customer-cloud-site.atlassian.net",
"name": "Migration Plan Name"
},
"key": "e094ca53-3747-4541-b263-0bf7b56a5bca",
"label": "file-label-you-used",
"serverAppVersion": "1.0",
"messageId": "53f88ea7-a2d2-4dd2-9f36-2d8c43401b11"
}
For Connect apps:
Connect apps can utilise existing Connect app migration APIs with respective transfer IDs of each transfer.
Sample Connect Event Payload (for a Jira migration) :
{
"eventType": "app-data-uploaded",
"cloudAppKey": "my-cloud-app-key",
"transferId": "6c01ac6f-c512-4ef7-8b48-25c1803fe305",
"lastDeltaMigrationTimestamp": "2025-08-18T15:30:04Z",
"deltaMigrationTimestamp": "2025-08-21T01:57:32Z",
"migrationDetails": {
"migrationId": "403c4f71-a0d1-4a63-97a8-487d18691c46",
"migrationScopeId": "0ba07dd9-3804-4600-9102-fa6e1efeab08",
"createdAt": 1723111376499,
"cloudUrl": "https://your-customer-cloud-site.atlassian.net",
"name": "Migration Plan Name"
"jiraClientKey": "acb711b8-a878-356e-abbf-1ae1730308a2",
"confluenceClientKey": "unknown"
},
"s3Key": "e094ca53-3747-4541-b263-0bf7b56a5bca",
"label": "file-label-you-used",
"serverAppVersion": "1.0",
"messageId": "53f88ea7-a2d2-4dd2-9f36-2d8c43401b11"
}
Workflow for Delta Migrations:
Delta migrations initially will follow a similar flow to traditional app migrations.
-
Prior to the listener being triggered, listener.isDeltaMigrationSupported() is evaluated.
-
If false the existing migration flow is executed with listener.onStartAppMigration().
-
Otherwise a delta migration is executed with listener.onStartDeltaMigration().
-
-
listener.onStartDeltaMigration() can use the aforementioned getLastDeltaMigrationTime() and getPaginatedDeltaContainers() to calculate and migrate their app delta data.
Change Detection
The containers returned by DeltaAppCloudMigrationGateway.getPaginatedDeltaContainers() are only containers that have had core product data changed. This includes core entities such as: issues, pages, comments etc.
We will not be able to track app-specific data changes, including: AO Tables, Files, Custom Fields, Entity Properties etc, we expect our marketplace partners to be responsible for tracking any of those changes by using DeltaMigrationDetailsV1.getLastDeltaMigrationTime().
Asks
We welcome your feedback on this RFC: whether it’s a simple acknowledgment, or more detailed insights. We are particularly interested in your thoughts on the following points:
-
As Marketplace Partners, what information do you need to understand the differences between two migrations for reconciliation? Is providing timestamps of previous delta migrations and projects that contain modified issues enough for you to work out changes in app specific data?
-
As a Marketplace Partner, can you update specific entries in a project’s cloud app specific data without rewriting everything?
-
Beyond the timestamp of the previous delta migration sent to the cloud app during each transfer, what other information would help determine changes between delta migrations for the cloud app?
-
Do you have any extension ideas for the proposed solution? If so, please share your ideas or use cases.