Find Your Jira’s Hidden Custom Field Waste
4 SQL queries that expose unused, duplicate, and abandoned fields
Before You Start: The Exclusion Rule
One critical caveat before running any queries: some “empty” fields aren’t actually empty.
Jira Service Management, Jira Software (the agile features), Capture, and Portfolio for Jira store their custom field data in separate datastores — not in the standard customfieldvalue table. If you query that table, these fields will appear unused even when they’re actively in use.
Every query below excludes these field types:
AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.servicedesk%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.pyxis.greenhopper%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.bonfire%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.jpo%'
You don’t want to delete your Sprint field because a query said it was “unused.”
Completely Unused Fields LOW RISK
These fields exist in your system but have never contained data. Zero values. Ever.
SELECT cf.id, cf.cfname, cf.description, cf.CUSTOMFIELDTYPEKEY FROM customfield cf LEFT JOIN customfieldvalue cfv ON cf.id = cfv.customfield WHERE cfv.id IS NULL AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.servicedesk%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.pyxis.greenhopper%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.bonfire%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.jpo%' ORDER BY cf.cfname;
What you’ll find:
- Fields created “just in case” that were never used
- Fields from plugins that were uninstalled
- Duplicate fields created by mistake and then abandoned
- Test fields someone forgot to delete
If a field has never held data, deleting it won’t cause data loss. But still check if it’s referenced in screens, workflows, or automation rules before removal.
Low-Usage Fields MEDIUM RISK
These fields have data, but barely. Maybe 5 issues out of 100,000.
SELECT COUNT(*) as usage_count, cf.id, cf.cfname, cf.CUSTOMFIELDTYPEKEY FROM customfield cf LEFT JOIN customfieldvalue cfv ON cf.id = cfv.customfield WHERE cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.servicedesk%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.pyxis.greenhopper%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.bonfire%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.jpo%' AND cfv.id IS NOT NULL GROUP BY cf.id, cf.cfname, cf.CUSTOMFIELDTYPEKEY HAVING COUNT(*) < 50 ORDER BY usage_count ASC;
Adjusting the threshold:
The < 50 threshold is a starting point. Scale it to your instance:
| Total Issues | Suggested Threshold | Logic |
|---|---|---|
| 10,000 | < 10 | 0.1% of issues |
| 100,000 | < 100 | 0.1% of issues |
| 500,000 | < 500 | 0.1% of issues |
The 0.1% rule comes from The Jira Guy's recommendation: if fewer than one-tenth of one percent of issues use a field, it's worth questioning whether that field should exist globally.
What you'll find:
- Project-specific fields that got global context by mistake
- Fields from completed/archived projects
- Experimental fields that didn't get adoption
- Fields replaced by newer alternatives but never cleaned up
There's data here, so you need to decide: migrate it, archive it, or accept losing it.
Duplicate Field Names HIGH RISK
The classic "which Priority field is the real one?" problem.
SELECT cfname, COUNT(*) as duplicate_count FROM customfield GROUP BY cfname HAVING COUNT(*) > 1 ORDER BY duplicate_count DESC;
What you'll find:
- Fields created by different admins who didn't check existing fields
- Test/production duplicates that both ended up in production
- Fields with slightly different configurations (different options, different contexts) but same name
Duplicate names create chaos: Users select the wrong field on forms. JQL searches return unexpected results. Reports pull from inconsistent data sources. New admins can't tell which field to use.
Next step: For each duplicate, run this to see which projects actually use each variant:
SELECT DISTINCT p.pkey as project_key, cf.id, cf.cfname FROM customfield cf JOIN customfieldvalue cfv ON cf.id = cfv.customfield JOIN jiraissue ji ON cfv.issue = ji.id JOIN project p ON ji.project = p.id WHERE cf.cfname = 'Your Duplicate Field Name' ORDER BY p.pkey, cf.id;
HIGH for confusion, MEDIUM for deletion. You can't just delete one — you need to audit which projects use which field, potentially merge data, and update screens/workflows.
Abandoned Fields MEDIUM RISK
These fields exist, have historical data, but haven't been touched in a long time.
SELECT cf.id, cf.cfname
FROM customfield cf
WHERE cf.cfname NOT IN (
SELECT item.field
FROM changeitem item
JOIN changegroup cg ON item.groupid = cg.id
WHERE item.fieldtype = 'custom'
AND cg.created > '2024-01-01'
)
AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.pyxis.greenhopper%'
AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.servicedesk%'
AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.bonfire%'
AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian.jpo%'
ORDER BY cf.cfname;
Adjust the date ('2024-01-01') to your preferred lookback period:
| Lookback Period | Approach |
|---|---|
| 6 months | Aggressive cleanup |
| 12 months | Balanced approach |
| 24 months | Conservative |
What you'll find:
- Fields from deprecated processes
- Fields tied to completed long-term projects
- Fields that teams stopped using but never formally retired
- Historical tracking fields no longer relevant
The data exists but isn't being maintained. Question whether it still has business value before removal.
Bonus: Fields Created by Third-Party Plugins
Not all plugin fields are bad, but it's useful to know which plugins have left their mark:
SELECT cf.cfname, cf.CUSTOMFIELDTYPEKEY FROM customfield cf WHERE cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.atlassian%' AND cf.CUSTOMFIELDTYPEKEY NOT LIKE '%com.pyxis%' ORDER BY cf.CUSTOMFIELDTYPEKEY, cf.cfname;
What you'll find:
- Fields from currently installed plugins (expected)
- Fields from uninstalled plugins (cleanup candidates)
- Fields from trial plugins you tested years ago
Cross-reference with your installed plugins list. Any field type from a plugin that's no longer installed is safe to investigate for deletion.
Running These Queries
If you have read-only database credentials:
psql -h your-db-host -U readonly_user -d jiradb -f audit_queries.sql
Tools like Home Directory, Database & Log File Browser for Jira let you run these queries directly from Jira's admin interface:
- Navigate to the Database Browser
- Paste query
- Execute
- Export results to CSV
No SSH, no terminal, no database client installation.
If you don't have database access, send these queries to your DBA with an explanation. They'll appreciate that you came with specific, read-only queries rather than vague requests.
Organizing Your Results
After running all four queries, you should have:
| Query | Fields Found | Risk Level |
|---|---|---|
| Unused | [your count] | Low |
| Low-usage | [your count] | Medium |
| Duplicates | [your count] | Medium-High |
| Abandoned | [your count] | Medium |
Create a spreadsheet with columns:
- Field ID
- Field Name
- Category (Unused/Low/Duplicate/Abandoned)
- Plugin source (if applicable)
- Decision (Delete/Keep/Investigate/Merge)
- Notes
This becomes your cleanup roadmap.
You now have a list of candidates. Do not mass-delete them.
Before removing any field, you need to verify:
- Is it used in any saved filters?
- Is it displayed on any dashboard gadgets?
- Is it referenced in workflow conditions, validators, or post-functions?
- Is it used in automation rules?
- Is it referenced in ScriptRunner scripts or behaviors?
A field can have zero data in customfieldvalue but still be actively referenced in your configuration. Deleting it will break things.
That verification process — and the safe deletion workflow — is exactly what we'll cover in Part 3.
The Bottom Line
You now have data-driven answers to the question "which custom fields should I clean up?"
Not hunches. Not "this looks old." Actual query results showing:
- Fields with zero data (easiest wins)
- Fields barely anyone uses (worth questioning)
- Fields with duplicate names (causing confusion)
- Fields nobody's touched in 12+ months (probably forgotten)
This is your hit list. Part 3 will show you how to safely execute on it.
This article is Part 2 of the "Custom Field Health Check" series for Jira Data Center administrators.
SQL queries validated for Jira Data Center 10+ on PostgreSQL. Original query patterns from The Jira Guy, updated and tested for current Jira versions based on Atlassian's schema documentation.