How to assess the impact of too many Custom Fields in Jira and how to resolve it

Platform Notice: Data Center Only - This article only applies to Atlassian products on the Data Center platform.

Note that this KB was created for the Data Center version of the product. Data Center KBs for non-Data-Center-specific features may also work for Server versions of the product, however they have not been tested. Support for Server* products ended on February 15th 2024. If you are running a Server product, you can visit the Atlassian Server end of support announcement to review your migration options.

*Except Fisheye and Crucible

Summary

Too many custom fields can compromise the performance of Jira instances, as disclaimed on Jira Software guardrails — but more specifically, it's the number of custom fields with context that's most impactful.

Having too many custom fields may impact the performance of some admin functionalities, but having too many fields in a given Issue's context (Project + Issue Type) is what impacts end-users on almost every Jira operation. The impact is even higher when many fields have default values, which adds an overhead in Jira to persist and load the field values at every operation, even if they're not really used by the Issue.

This article shows one possible way to assess the number of fields impacting any given Issue and shares some advices on how to optimize them.

Solution

Admins are advised to regularly perform cleanup/housekeeping activities in Jira:

The below steps focus on the number of Custom Fields only.

Overview

Here's what we can do on a high level approach:

  1. Determine which fields are indexed in sample Issues and which are non-empty

  2. Validate the time with an almost empty Field Configuration (baseline)

  3. Determine which fields are really in use for given Projects or Issue Types

  4. Narrow the custom fields contexts to what's only needed

1. Determine which fields are indexed in sample Issues and which are non-empty

For a given Project, create an Issue with just the required fields populated in the create screen.

Now access this URL and save the output to a file like JIRA-12345.json, replacing JIRA-BASE-URL and JIRA-12345 by your instance's URL and the newly created Issue Key, respectively:

1 https://JIRA-BASE-URL/rest/api/2/issue/JIRA-12345

On a Linux-like terminal, you can run these commands to get these stats from this issue:

Indexed custom fields

1 $ cat JIRA-12345.json | jq | grep -E '^\s*"customfield_[0-9]+":' | grep -E -o "customfield_[0-9]+" | wc -l

Non-empty custom fields

1 $ cat JIRA-12345.json | jq | grep -E '^\s*"customfield_[0-9]+":' | grep -E -v '^\s*"customfield_[0-9]+": null,' | grep -E -o "customfield_[0-9]+" | wc -l

Non-empty text custom fields

1 $ cat JIRA-12345.json | jq | grep -E '^\s*"customfield_[0-9]+":' | grep -E -v '^\s*"customfield_[0-9]+": null,' | grep -E '^\s*"customfield_[0-9]+": "' | grep -E -o "customfield_[0-9]+" | wc -l

Non-empty Select custom fields

1 $ cat JIRA-12345.json | jq | grep -E '^\s*"customfield_[0-9]+": {' -A5 | grep '"disabled": false' -B5 | grep -E -o "customfield_[0-9]+" | wc -l

To list the field identifiers in each section, simply remove the last | wc -l portion of each command.

If you don't have jq installed, you can either install it or save the JSON file already "prettified", instead of a continuous chunk of characters with no line breaks. (jq is being used to simply break the JSON file in many lines)

Click to expand AN EXAMPLE

Example

1 2 3 4 5 6 7 8 9 10 11 $ cat JIRA-12345.json | jq | grep -E '^\s*"customfield_[0-9]+":' | grep -E -o "customfield_[0-9]+" | wc -l 1916 $ cat JIRA-12345.json | jq | grep -E '^\s*"customfield_[0-9]+":' | grep -E -v '^\s*"customfield_[0-9]+": null,' | grep -E -o "customfield_[0-9]+" | wc -l 380 $ cat JIRA-12345.json | jq | grep -E '^\s*"customfield_[0-9]+":' | grep -E -v '^\s*"customfield_[0-9]+": null,' | grep -E '^\s*"customfield_[0-9]+": "' | grep -E -o "customfield_[0-9]+" | wc -l 196 $ cat JIRA-12345.json | jq | grep -E '^\s*"customfield_[0-9]+": {' -A5 | grep '"disabled": false' -B5 | grep -E -o "customfield_[0-9]+" | wc -l 118

On this example, the JIRA-12345 has 1916 indexed custom fields.

Of these 1916, 380 have default values: 196 are text fields with a default text in them and 118 are Select fields with a default option selected.

The creation of such issues would take around 12–13 seconds on a customer Production instance. Once we removed the unused fields from the context, it went down to ~2 seconds. This is highly dependent on the Jira installation which and how 3rd party Apps are used and the amount of data and usage load — it's a mere example, not a benchmark.

2. Validate the time with almost empty field configuration (baseline)

To have a baseline for optimization, we may create an empty Field Configuration and apply it on a test Project. There's a Groovy script we can use to empty a given Field Configuration, taken from Advanced cleanup:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.fields.layout.field.FieldLayoutManager import com.atlassian.jira.issue.fields.layout.field.EditableFieldLayout import com.atlassian.jira.issue.fields.layout.field.FieldLayoutItem FieldLayoutManager fieldConfigurationManager = ComponentAccessor.getComponent(FieldLayoutManager) EditableFieldLayout fieldConfiguration = fieldConfigurationManager.getEditableFieldLayout(99999L) // Replace Id here List<FieldLayoutItem> items = fieldConfiguration.getFieldLayoutItems() items.each { try { fieldConfiguration.hide(it) } catch (ignored) {} } fieldConfigurationManager.storeEditableFieldLayout(fieldConfiguration)

Replace the 99999L on line #6 by the Field Configuration you created and want to have it emptied (leave the L at the end). We can use any 3rd party app that allows the execution of an ad-hoc Groovy script.

You may apply this Field Config to a given Issue Type on a Project and compare how long it takes for Jira to create an Issue with this Field Config to others on the same Project with another Issue Type.

You may add more Fields to the Field Config as needed for a baseline that's more realistic.

Please note the ideal solution is to edit the Custom Fields Contexts to reduce their scope — the Field Configuration cleanup may be quicker to implement (with the script), but new Custom Fields are automatically added to all Field Configurations, whereas the Custom Fields' Contexts remain unchanged until Admins update them.

The Field Configuration optimization may work as a temporary solution until the Contexts are optimized or for a Proof Of Concept (POC) for the optimization.

3. Determine which fields are really in use for given Projects or Issue Types

The most assertive approach would be to delegate the task of listing which fields are used by each Project to the Project Admins or "Business Owners", but the below procedures may help them or the Jira Admin have a good head-start on which fields are actually in use.

The procedures below don't eliminate the need for manual/visual validation of end-users, as there may be false-positives and missing fields.

  1. List the fields present in any Screen

  2. List the fields that were ever changed for that Project and Issue Type

You can run the DB query from this How to list all fields and screens in use by a Project in Jira article and work with the exported spreadsheet. It'll show you all the fields present in any Screen used by a given Project — be it a Create/Edit/View Screen or a Workflow Screen (shown when changing the status of an Issue).

There are cases, though, that a field not present in any Screen is still relevant for the users, like hidden fields with automated calculations and updates or something. This other DB query lists all custom fields that were ever changed for a given Project after a certain date:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 SELECT p.pkey, CASE WHEN ci.fieldtype = 'custom' THEN CASE WHEN cf.id IS NOT NULL THEN CONCAT('customfield_', CONCAT(cf.id, CONCAT(' (', ci.field, ')'))) ELSE ci.field END ELSE ci.field END AS "Custom Field Identifier", COUNT(*) AS "Count" FROM changeitem ci JOIN changegroup cg ON cg.id = ci.groupid JOIN jiraissue i ON i.id = cg.issueid JOIN project p ON p.id = i.project LEFT JOIN customfield cf ON cf.cfname = ci.field WHERE ci.newvalue IS NOT NULL OR ci.newstring IS NOT NULL AND p.pkey = 'JIRA' AND cg.created >= '2023-01-01' GROUP BY p.pkey, ci.fieldtype, cf.id, ci.field ORDER BY p.pkey ASC, COUNT(*) DESC;

Replace JIRA and 2023-01-01 by the desired Project Key and cutover date.

The output lists the Project, the field identifier and the number of updates each custom field had. A higher value indicates a commonly used field, while a lower value may indicate a field with little usage, but again, this is just a head-start and manual validation is needed.

4. Narrow the custom fields contexts to what's only needed

This step, unfortunately, is laborious and time-consuming for Admins. It consists of updating each custom field's context to remove the Projects the field is not being used on.

Joining the fields from the first and second query of step #2 will give you the fields that are potentially in use by a given Project. The fields that are in neither list are probably not being used and are good candidates to be removed from the context of that Project, if the manual validation doesn't overrule such assessment.

If unsure about some fields and the steps above weren't helpful to determine if they're used or not, we may rely on Jira searches with JQL queries, like:

1 project = JIRA and "Some Custom Field" is not empty order by "Some Custom Field"

Add the "Some Custom Field" to the result columns and you may check if they all have the same (default) value or if this provide any other insight.

Updated on March 17, 2025

Still need help?

The Atlassian Community is here for you.