Preparing for Jira 9.0

This documentation is intended for Jira developers who want to ensure that their existing apps are compatible with Jira 9.0 

Quick info

Latest version

Here you can find information about the latest EAPs.

Application / Date


Version (Maven)


Jira Core/Software




Source files (Core)

Source files (Software)

Jira Service Management




Source files

Summary of changes

In this section we'll provide an overview of the changes we intend to make, so you can start thinking how it might impact your apps. Once they're ready, we'll indicate when a change has been implemented, and in which milestone. 

Automation for Jira (Data Center)

Status: IMPLEMENTED (eap 01)

With the release of Jira 9, Automation for Jira will become a native feature, bringing additional value to Data Center customers. This feature will be available both in Jira Software and Jira Service Management for automated, effective work. Automation for Jira will continue to be available in Jira 9 also for Server customers but will require an existing paid license.

The feature is still under development and minor changes related to configuration of the feature may be introduced.

Limit excessive activity with the Guardrails Tool

Status: IMPLEMENTED (eap 02)

In the previous release, we introduced the Guardrails Tool to help you minimize performance drops or crashes resulting from exceeding a certain number of comments per issue in your Jira instance. As of 02, we’re calling this feature “Safeguards”.

If you rely heavily on automation, Safeguards can help you moderate a bot account group’s activity by limiting the number of comments every account in that group can add to an issue. The tool can also block activity that would result in breaking that safeguard, which can help boost the performance of loading the issue view.

Safeguards will also alert you by email if the number of comments in an issue is approaching the limit (either default or custom), the limit has been reached, or the limit has been exceeded. If you define a moderated group in the settings, you will also start receiving notifications about certain activity having been blocked. By default, the limit of comments per issue is set to 1000.

Learn how to configure Safeguards

“View on board” gets a redesign for better performance

Status: IMPLEMENTED (eap 02)

We’ve replaced the old way of viewing issues on boards with an entirely new experience aimed at improving the responsiveness of searching for boards that display a particular issue.

Now, instead of searching through every board in the system, Jira will only search the boards that make explicit mention of an issue’s project key and the boards you viewed recently. This way, you’ll get more meaningful results much quicker than before.

To try it out, open the full issue view and select Find on a board from the Agile panel.

Search index health improvements

Status: IMPLEMENTED (eap 02)

Jira 9.0 brings changes to indexing issue, comment, and worklog versions that improve the maintenance of index health, but break backwards compatibility with previous releases of Jira.

What has changed?

Starting with Jira 9.0, all issue, comment, and worklog version indexes must now be created and stored both in the Lucene search index and the database. Additionally, it’ll no longer be possible to create index snapshots on Data Center nodes with corrupted indexes.

All index snapshot now use the same file naming scheme regardless of their location:


The index file and snapshot locations have also changed:

  • <local_home_directory>/caches/indexesV2 stores index files
  • <shared_home_directory>/caches/indexesV2/snapshots stores index snapshots that were:
    • created by scheduled index backups
    • retrieved by nodes joining the cluster
    • used for snapshot recovery
    • replicated to the secondary home directory
  • <shared_home_directory>/caches/indexesV2/snapshots stores index snapshots created:
    • on the completion of a full reindex and retrieved by other nodes on reindex detection
    • when a new node joined the cluster
    • on administrator request
    • on data import

The <shared_home_directory>/import/indexsnapshots directory remains unchanged. This location stores manually copied index snapshots used for restoration in case of a disaster recovery.

What do I need to know?

Upgrading to release 9.0 in a clustered Data Center configuration involves some downtime on the primary node to allow Jira to generate and reindex versions for all issues, comments, and worklogs in the system as well as perform a full foreground reindex.

tip/resting Created with Sketch.

To reduce upgrade downtime and keep your Jira 8.x Data Center cluster operational for as long as possible, we’ve prepared a minimal downtime upgrade procedure. Learn how to perform a minimal downtime upgrade to Jira 9.0

During upgrade, the following index directories and their content will be removed automatically:

  • Jira 8.x index directories:
    • <shared_home_directory>/caches/indexesV1 (clustered Data Center configurations only)
    • <local_home_directory>/caches/indexesV1
  • pre-Jira 8.x index directories:
    • <shared_home_directory>/caches/indexes (clustered Data Center configurations only)
    • <local_home_directory>/caches/indexes

Legacy Data Center node index snapshots will remain at their current locations:

  • <shared_home_directory>/export/snapshots
  • <shared_home_directory>/caches/

Legacy index snapshots are not compatible with Jira 9.0 and using them to restore the index may cause search consistency and performance issues. As such, we recommend that you delete the legacy snapshot directories and their content manually when the upgrade is completed.

Lazy-loading workflow transitions

Status: IMPLEMENTED (eap 01)

We’ve moved all the transition buttons to the dropdown menu. We're now rendering all of the Jira transitions in the dropdown asynchronously on-demand after a user opens the dropdown.

We’ve also removed the status field and View workflow link from the issue details section. The View workflow link is now shown as an option in the dropdown. The current status is presented in the trigger label.

What do I need to know?

  • For complicated workflows, the dropdown will be very tall and hard to use in windows with small heights.

  • The dropdown is now wider than before that so it can be clipped in windows with a very small width.

  • We cannot distinguish between the case that the user has no permissions to transition the status or if the issue is already in a status that has no possible transitions. For such cases, we display user assistance.

Lazy-loading attachments' thumbnails on issue view

Status: IMPLEMENTED (eap 01)

We’ve sped up the loading time of issues with a significant number of attachments. With the new functionality, thumbnails generation is deferred and asynchronous for the issue view by default. It speeds up page loading and reduces the amount of data processed at once.

To disable the functionality you need to setcom.atlassian.jira.thumbnailsDeferredGeneration.disabled parameter.

The attachment lazy-loading feature outside of the Issue view is disabled by default.

To enable the functionality you need to set com.atlassian.jira.allThumbnailsDeferred.enabledin /secure/SiteDarkFeatures!default.jspa parameter.

Lazy-loading inline gadgets

Status: IMPLEMENTED (eap 02)

To ensure faster loading of Jira dashboards, we’re introducing a lazy loading mechanism for inline gadgets that are displayed on the dashboard view. With this improvement implemented, only inline gadgets present in the viewport will be loaded on the page load.

What has changed?

From now on, the following inline gadgets are lazy-loaded: Assigned to Me, Bubble Chart, Created vs Resolved Chart, Favourite Filters, Filter Results, Issues in progress, Issue Statistics, Labels, Pie Chart, Two Dimensional Filter Statistics, Voted Issues, Watched Issues.

We're planning to introduce a lazy loading mechanism to other gadgets, including the ones embedded inside iframes.

What do I need to know?

We encourage you to update your gadgets so that they support lazy-loading logic. To help you with this, we’ve added the AMD module that you can reuse like this:

define('your gadget path', 
['jira/jira-dashboard-items/components/lazy-loading/lazy-loading'], function (
) {

return lazyLoading
	.then(() => yourGadgetLogic())

Front-end API contract

Status: IMPLEMENTED (eap 02)

Jira 9.0 comes with the API front-end contract that brings more clarity and efficiency to your app development process.

So, what’s in this for you?

  • You’ll know for sure when any changes should be expected so you can prepare your apps in advance.
  • You can make your apps faster and better by using explicitly provided APIs. The list of official APIs can be expanded based on your feedback.
  • The front-end contract provides guarantees we make to stabilize front-end components.

Check the front-end contract for all the details. We’re open for collaboration, so if you have any questions or need assistance—just let us know.

Activity tabs improvements

Status: IMPLEMENTED (eap 02)

As announced in the previous , we’re optimizing the way activity items for the Comments, History, Work Logs, and All tab are displayed and organized in Jira Issue View. With the new functionality, Jira issues will load much faster, even if they contain thousands of activity tab events, like comments or work logs.

What has changed?

We’ve introduced the new progressive date-based pagination system that allows to incrementally load events for activity tabs. Users no longer need to load everything to view the oldest events. Instead, they can select between two options:

  • Load 10 older events. If users load the last remaining events on the activity tab, fewer items might be loaded. If several events have the same creation date, more items might be loaded.
  • Load all older events. This might change in further releases as we work on fixing the Out of Memory error. As a possible solution, we might only allow loading the number of events that wouldn't cause the error.

We’ve changed the way sorting works. From now on, users can easily access both the oldest and newest events (e.g. work logs) first, without loading all those that are in-between (until now, Jira reordered the newest elements only).

How do I enable the feature?

This feature is enabled by default and cannot be turned off.

What do I need to know?

If you want to display your content on the All tab, you will have to implement a new API interface.

Known issues

  • If the user is editing an event (e.g. comment) that's not on the list of either 10 first or 10 last items to load, this event will disappear from view and they will have to search for it. This is also a known issue in Jira 8. Addressing this behavior is possible, but it would require high effort to ensure that we don't break the existing functionality. 
  • If sorting happens after all events for an activity tab are loaded, the sorting state won’t be remembered.

New checkpoints for resource phases

Status: IMPLEMENTED (eap 04)

Adding these new checkpoints to your Jira pages is optional. You might only do this if you’re using the WRM 5 APIs and have the DEFER and INTERACTION phases for requiring your resources or embed your scripts on pages that use these phases.

As part of the Jira App header improvements, we’ve added two new checkpoints that will be always available on Jira pages and get resolved when:

  • DEFER phase resources are available. To execute logic once defer checkpoint is hit, use: resourcePhaseCheckpoint.defer.then(deferPhaseCallback);
  • During the INTERACTION resource phase. To execute logic once interaction checkpoint is hit, use: resourcePhaseCheckpoint.interaction.then(interactionPhaseCallback);

For more information about resource phases in WRM-related-places, see the CHANGELOG.

I don't see resourcePhaseCheckpoint on my Jira page

New checkpoint promises are provided by Jira pages by default. However, if your newly created page doesn’t have them, you can add these new checkpoints as follows:

  • requireWebResource(ResourcePhase.INLINE, "jira.webresources:resource-phase-checkpoint-init");. Should be added at the top of the page so that it starts executing as soon as possible.
  • requireWebResource(ResourcePhase.DEFER, "jira.webresources:resource-phase-checkpoint-hit");. Should be added at the bottom of the page so that it starts executing as late as possible.

App header updates

Status: IMPLEMENTED (eap 04)

We've made changes to the App header, which allow us to load it faster. We’ve updated the way Jira renders the following pages. The changes will affect your plugins if they execute .js scripts on these pages:

  • Issue View: <your Jira URL>/browse/ISSUEKEY-1
  • Project-centric Issue Navigator: <your Jira URL>/projects/MNSTR/issues/ISSUEKEY-1?filter=allopenissues
  • Global Issue Navigator: <your Jira URL>issues/?jql=
  • Dashboard (including system dashboard): <your Jira URL>/secure/Dashboard.jspa?selectPageId=1

All the .js resources on the above-listed pages are now deferred. Additionally, we’ve adjusted the Flush Head Early mechanism for these pages—it sends a partially rendered markup with resource (.css, .js) definitions and an animated app header placeholder before doing heavy work on the back-end.

What do I need to know?

Deferring scripts in Jira

We use new capabilities of Web Resource Manager (WRM), available in 5.0 and later—loading of .js resources in defer phase. You can learn more about these WRM changes in the CHANGELOG.

In practice, the <script> tags in markup generated by will have an additional defer attribute (see the  specification for details), like this:

<script src="/s/(...)/jira.general,-_super/batch.js" (...) defer></script>

With this attribute, deferred scripts will be executed just after the browser parses all the markup on the page and before the DOMContentLoaded event.

All global variables (e.g. jQuery or AJS) and AMD modules (e.g. jira/flag) won’t be accessible on pages with deferred scripts. To address this:

  • Use WRM 5 APIs to defer the scripts your plugin requires on the pages with deferred .js resources.
  • Use inline scripts (no src attribute) with type="module" attribute.
  • Postpone the execution of the script until DOMContentLoaded or later event occurs.
  • It’s even better to use the interaction phase when the logic can be initialized after the DOMContentLoaded event.

To execute .js resources on pages with deferred scripts, use methods that were introduced by WRM 5 to com.atlassian.webresource.api.assembler.RequiredResources that accept com.atlassian.webresource.api.assembler.resource.ResourcePhase. Use com.atlassian.jira.web.RequestAssetPhaseStore to get the ResourcePhase that’s currently used on the page.

For new APIs usage examples, check the com.atlassian.jira.web.action.Dashboard#doExecute.

BigPipe is no longer supported

Status: IMPLEMENTED (eap 02)

BigPipe is a server-side lazy-loading technique that was used to defer the rendering of Jira web panels.

If you’re using BigPipe in your apps, we recommend switching to other lazy-loading techniques. You can use an AJAX call to fetch the content of the panel or client-side rendering instead.

Replacing core Jira components is no longer possible

Status: IMPLEMENTED (eap 02)

Overriding core Jira components is a legacy feature available in the Plugins1 system. This technique has been deprecated in JIRA 4.3 and later, and we’re removing it completely in Jira 9.0.

What do I need to know?

This change affects only legacy apps that are still using the Plugins1 system.

Popper replaces Tipsy in 9.3.5

Status: IMPLEMENTED (eap 01)

We’ve upgraded to version 9.3.5, which replaces the Tipsy tooltip generation library with Popper. To make sure that your tooltips still work with the upgraded , you may need to make some changes:

  • no longer supports the data-tooltip attribute. Instead, use the title attribute on the element to which a tooltip should be attached.

  • Tooltips will appear even if the title is empty. To prevent that from happening, destroy the tooltip by calling the $el.tooltip('destroy') function.

  • To pass markup to the tooltip, call $el.tooltip({ html: true }).

Replace the tipsy.revalidate() method with $el.tooltip('destroy').

Restricting anonymous access to endpoints

Status: IMPLEMENTED (eap 01)

We’ve restricted anonymous access to the following API endpoints:

  • /rest/api/2/issueLinkType

  • /rest/api/2/priority

  • /rest/api/2/projectCategory

  • /rest/api/2/resolution

  • /rest/api/2/status

  • /rest/api/2/statuscategory

  • /rest/api/2/projectvalidate/key?key=

  • /rest/api/2/jql/autocompletedata/

  • /rest/api/latest/avatar/project/system

  • /rest/api/2/field

  • /rest/api/2/screens

  • /rest/api/1.0/issues/<issueId>/ActionsAndOperations

From now on, anonymous users attempting to perform GET requests on the previously listed endpoints will receive a “401 Unauthorized” response code.

Improved XSRF protection

Status: IMPLEMENTED (eap 01)

We’ve changed the XSRF protection default policy for web actions:

  • XSRF (or CSRF, Cross-Site Request Forgery) is an old attack class and Jira is already equipped with XSRF countermeasures since Jira 4.1 (2009) - token checks - for both API and WebWork routes (aka web actions). However, before Jira 9 web actions were only protected if their code was annotated with the @RequiresXsrfCheck annotation, meaning it is the developers' responsibility to opt-in for XSRF token checks provided by Jira Core. In the wild, the opt-in approach means a risk of unprotected web actions and a successful XSRF attack.

  • This will change in Jira 9. Web actions invoked with POST/PUT/PATCH/DELETE HTTP methods (or actually whatever HTTP method other than GET, HEAD, OPTIONS or TRACE) will be subject to XSRF token checks by default unless the action code is annotated with @DoesNotRequireXsrfCheck a new explicit opt-out annotation.

  • To temporarily revert the default to the old one (Jira 8’s opt-in XSRF check policy) the jira.webactions.request.method.dependent.xsrf.checks.disable feature flag may be used.

What is changing?

Changes may be required for web actions invoked with POST/PUT/PATCH/DELETE having no @RequiresXsrfCheck annotation in Jira 8. Here are the general guidelines to follow while adapting to the new XSRF policy:

For truly safe actions, i.e. actions without state modifying side-effects (like pure reads or searches) simply change your front-end pieces to use GET (or HEAD or OPTIONS) HTTP method instead of POST/PUT/PATCH/DELETE. If you have a good reason to stick to POST/PUT/PATCH/DELETE (e.g. GET URL may become too long for certain supported browsers, therefore you choose to make POST as a workaround for browser’s limitation) - you may want to either:

- annotate your action with @DoesNotRequireXsrfCheck - but remember to use it with caution and to justify each usage in code comments,

- add an XSRF token as you would do for state-modifying actions.

For all other actions (i.e. for unsafe / state-modifying actions) change the front-end pieces to include XSRF token in the atl_token request parameter - exactly same way as you would do implementing action with @RequiresXsrfCheck in Jira 8.

Verification of Jira web action request methods

Status: IMPLEMENTED (eap 02)

We’ve added an additional security check for Jira web actions that verifies the HTTP method that an action is invoked with to prevent the new opt-out XSRF check from being bypassed. By default, the XSRF check works only for non-safe HTTP methods (for example, POST or DELETE). With this check, attempts at invoking an action with a malicious link will cause Jira to block the action and display the “405: Method Not Allowed” HTTP response code.

Both new and existing web actions must now define the supported methods with the class-level annotation or with a method-level annotation on a command method (like String do<Something>). A method-level annotation overrides the class-level annotation. Classes and methods without an annotation will only accept POST requests. For example:

static class SampleAction extends JiraWebActionSupport {
    public String doTest(){
        return INPUT;

Here, SampleAction.jspa, SampleAction!default.jspa will only accept GET requests and SampleAction!test.jspa will only accept POST requests.

Additionally, we recommend that instead of calling the com.atlassian.jira.web.action.JiraWebActionSupport or webwork.action.ActionSupport classes directly, you create a subclass implementing the action and annotate its supported methods accordingly.

The check is enabled by default; however, if you run into app compatibility issues, you can disable it entirely by setting the jira.webactions.request.method.recognition.disabled feature flag.

Disabling the HTTP request method check is strongly discouraged in production environments as it degrades security and allows potential attackers to bypass the XSRF check.

API breaking changes

Status: IMPLEMENTED (eap 01)

Jira 9.0 introduces a number of breaking changes to the Java API. The following sections list the affected API classes, interfaces, methods, and dependencies.

Previously deprecated API classes and methods removed in this release...

Previously deprecated API classes and methods removed in this release

The following API classes and methods were previously deprecated and are now removed:

Other removed API classes and methods...

Other removed API classes and methods

The following API classes and methods were removed for reasons other than deprecation.


Removed to increase security by preventing remote code execution.


Removed from Jira Software’s @ExperimentalApi in order to allow a rework of the sprint cache.

Modified API classes and methods...

Modified API classes and methods

Following the ADGS adjustments and color changes we made in Jira 8, we've modified the com.atlassian.jira.issue.status.category#getColorName method in Jira 9.0.

The method now returns semantic names (like "inprogress" and "success") instead of obsolete color names. The semantic names now map to desired colors.

New API classes and methods...

New API classes and methods

The following interfaces, classes, and methods in the Jira DC Java API were added as a result of us removing deprecated items when the suggested alternative was missing some functionality or would have had different behavior.

Added the forceStrongConsistency parameter, which was needed in jira-core and may be needed in situations when consistency is important (for example, in the external communication or security context).

This parameter must force implementation to avoid returning stale data (for example, cached data).

This may affect the performance, so use only when really necessary.

Added isUserInGroups which was needed to expose access to DirectoryManager.isUserNestedGroupMember for the Safeguards comment limit.

This checks if a user is a member of any of the specified groups.

Performance is dependent on the implementation of caching in the underlying user directory.

Removed dependencies...

Removed dependencies

We removed the following Jira cross-compatibility library bridges exposed by Jira Core due to their incompatibility with Jira 9.0.x:

  • com.atlassian.jira.compat:jira-cross-compatibility-lib-bridge-api
  • com.atlassian.jira.compat:jira-cross-compatibility-lib-bridge-factory

If you were using the bridges provided by this library, migrate to Jira 9.0 interfaces.

We also removed commons-lang 2.x. Use commons-lang 3.x instead.

Dependencies moved to Jira Core...

Dependencies moved to Jira Core

The following dependencies were moved to the jira-core module:

  • com.twelvemonkeys.imageio:imageio-jpeg
  • com.twelvemonkeys.imageio:imageio-tif
  • com.atlassian.threadlocal:atlassian-threadlocal
  • com.atlassian.http:atlassian-http
  • org.apache.tika:tika-core

XStream allowlist for improved safety

Status: IMPLEMENTED (eap 02)

XStream is used for storing default values of custom fields inside the database. It serializes the default value to the and deserializes it back when it’s retrieved back. There is a security risk that lies in the deserialization part. If someone has access to the database, they can put containing malicious code that would be executed during the deserialization process. To prevent it, XStream 1.4.18 introduced allowlist, which contains the names of the classes that can be deserialized. If a class is not there, deserialization will fail with an exception. Jira 9.0 uses XStream 1.4.18 with the allowlist by default.

What’s changed?

Some apps that add custom field types will have to extend the allowlist with the class of its transport object. It’s required only if the class is not already on the allowlist. The current elements are listed below. If a line starts with class, it means that only the given class is allowed. If it starts with hierarchy, all its descendants are allowed:

class java.lang.Class
class java.lang.Object
class java.lang.StackTraceElement
class java.lang.String
class java.lang.StringBuffer
class java.nio.charset.Charset
class java.text.DecimalFormatSymbols
class java.time.Duration
class java.time.Instant
class java.time.LocalDate
class java.time.LocalDateTime
class java.time.LocalTime
class java.time.MonthDay
class java.time.OffsetDateTime
class java.time.OffsetTime
class java.time.Period
class java.time.Ser
class java.time.Year
class java.time.YearMonth
class java.time.ZonedDateTime
class java.time.chrono.HijrahDate
class java.time.chrono.JapaneseDate
class java.time.chrono.JapaneseEra
class java.time.chrono.MinguoDate
class java.time.chrono.Ser
class java.time.chrono.ThaiBuddhistDate
class java.time.temporal.ValueRange
class java.time.temporal.WeekFields
class java.util.BitSet
class java.util.Currency
class java.util.Date
class java.util.Locale
class java.util.regex.Pattern
hierarchy java.lang.Enum
hierarchy java.lang.Number
hierarchy java.lang.StringBuilder
hierarchy java.lang.Throwable
hierarchy java.lang.reflect.Member
hierarchy java.nio.file.Path
hierarchy java.sql.Date
hierarchy java.sql.Time
hierarchy java.sql.Timestamp
hierarchy java.time.Clock
hierarchy java.time.ZoneId
hierarchy java.time.chrono.Chronology
hierarchy java.util.Calendar
hierarchy java.util.Collection
hierarchy java.util.Map
hierarchy java.util.Map.Entry
hierarchy java.util.TimeZone
hierarchy java.util.UUID

Apart from that, all primitives and arrays are allowed. Find the definition of a transport object in our documentation.

Extending the allowlist

We’ve introduced that can be used for listing the classes that have to be added to the allowlist. Here’s an example implementation:

package com.atlassian.tutorial.jira.customfields;

import com.atlassian.diff.CharacterChunk;

import javax.validation.constraints.NotNull;
import java.util.HashSet;
import java.util.Set;

public class AllowlistProvider implements XmlPluginAllowlistProvider {
public @NotNull Set<String> getAllowlistedClasses() {
Set<String> set = new HashSet<>();
return set;

To be effective, the implementation has to be specified as a module inside the atlassian-plugin.xml file. The name of the module is xml-plugin-allowlist and it needs to have a key (some unique string) and class attributes. For example:

<xml-plugin-allowlist key="plugin.extensions" class="com.atlassian.tutorial.jira.customfields

  thread processing configuration


Status: IMPLEMENTED (eap 02)

We’ve added a new configuration setting that allows you to select the off-thread processing mode:

  • Multi-threaded serialized processing (Recommended). Cluster efficient, recoverable, and resilient. Should be the default processor.

  • Multi-threaded in-memory processing. Legacy processing mode. Only revert to it temporarily if instructed.

  • No background processing. All processing will be done in the request thread, locking the response until it’s finished. You might experience a significant delay to the response time.

To configure your  off-thread processing mode:

  1. Go to Administration > Applications.

  2. Select  configuration.

  3. Find the threads row and select Configure.

Known issues

  • It takes a long time to load any page (over 2 mins for batch.js). This seems to be only present for a very small amount of users.

Last modified on May 9, 2022

Was this helpful?

Provide feedback about this article

In this section

Powered by Confluence and Scroll Viewport.