JQL Cheat Sheet: The Queries You Keep Googling

JQL Cheat Sheet: Copy-Paste Queries for Jira Admins

JQL Cheat Sheet: The Queries You Keep Googling

For Jira admins who know JQL but forget the syntax every time

JQL Reference Guide

This isn’t a JQL tutorial. You already know what JQL is.

This is the page you bookmark and come back to when you can’t remember:

  • Why your != query is missing issues
  • Whether startOfWeek() means Sunday or Monday
  • That one date function syntax you always forget
  • How to search for issues in an Epic (and why it’s different in Cloud vs Data Center)

Everything here works on both Jira Cloud and Data Center unless noted otherwise.

The 7 Gotchas That Catch Everyone

Gotcha #1

!= Doesn’t Include Empty Values

This query looks correct:

JQL
assignee != "john"

But it’s missing every unassigned issue in your project.

WHY THIS HAPPENS

Jira follows SQL NULL logic. NULL != "john" returns false, not true. This is by design and won’t change — Atlassian marked it “Won’t Fix” in 2019.

THE FIX
CORRECT QUERY
assignee != "john" OR assignee is EMPTY

Same applies to NOT IN:

NOT IN EXAMPLE
-- Wrong (missing unassigned):
assignee NOT IN ("john", "jane")

-- Correct:
assignee NOT IN ("john", "jane") OR assignee is EMPTY
Pro tip: This catches people constantly. Bookmark this one.
Gotcha #2

startOfWeek() Returns Sunday, Not Monday

JQL
created >= startOfWeek()

You expected Monday. Jira gives you Sunday.

WHY THIS HAPPENS

Jira defaults to US locale where Sunday is the first day of the week. There’s an ISO8601 setting in Look and Feel, but it’s buggy and doesn’t always work.

THE WORKAROUND
WORKAROUND
-- Monday to Friday (actual work week):
created >= startOfWeek("+1d") AND created <= endOfWeek("-1d")

-- Monday to Sunday:
created >= startOfWeek("+1d") AND created <= endOfWeek("+1d")

The +1d shifts Sunday to Monday. Yes, it's annoying.

Gotcha #3

WAS and CHANGED Only Work on 6 Fields

You want to find issues where Sprint changed:

JQL
Sprint CHANGED FROM "Sprint 1" TO "Sprint 2"

Error. The WAS and CHANGED operators only work with:

  • Assignee
  • Fix Version
  • Priority
  • Reporter
  • Resolution
  • Status

That's it. No Sprint, no Issue Type, no Due Date, no Custom Fields.

Want history search for other fields? You need an app like Issue History for Jira or ScriptRunner.
BONUS GOTCHA FOR CLOUD

WAS/CHANGED are unreliable in team-managed (next-gen) projects. See JRACLOUD-72180.

Gotcha #4

Special Characters Don't Work in Text Search

JQL
summary ~ "[URGENT]"

This searches for URGENT, ignoring the brackets entirely.

WHY THIS HAPPENS

Jira's Lucene index strips special characters. They're not stored, so you can't search for them.

Characters that get ignored: + - . , ; ? | * / % ^ $ # @ [ ] ( ) { }

Escaping doesn't help — this is a known limitation since 2011, marked "Won't Fix":

DOESN'T WORK EITHER
summary ~ "\\[URGENT\\]"
Workaround: There isn't one in native JQL. Apps like JQL Search Extensions add regex support.
Gotcha #5

Wildcards Can't Start a Word

JQL
-- Works:
summary ~ "error*"     -- Finds: error, errors, errorCode

-- Doesn't work:
summary ~ "*error"     -- FORBIDDEN
summary ~ "?est"       -- FORBIDDEN

Jira explicitly blocks leading wildcards because they're extremely slow on large instances.

FOR EXACT PHRASE SEARCH
ESCAPE THE QUOTES
summary ~ "\"deployment failed\""
Gotcha #6

An Issue Can Be in Two Sprints Simultaneously

When you close a sprint, incomplete issues move to the next sprint. But they keep their link to the old sprint too.

JQL
-- Returns issues that were in Sprint 5, including those now in Sprint 6:
sprint = "Sprint 5"

-- Only issues that finished in Sprint 5:
sprint = "Sprint 5" AND sprint NOT IN openSprints()
AND THERE'S NO backlog() FUNCTION

To find backlog items:

BACKLOG QUERY
project = "PROJ" 
AND (sprint IS EMPTY OR sprint NOT IN (openSprints(), futureSprints())) 
AND resolution IS EMPTY
Gotcha #7

Epic Queries Are Different in Cloud vs Data Center

Data Center:

DATA CENTER
"Epic Link" = PROJ-123

Cloud (2023+):

CLOUD
parent = PROJ-123

Atlassian deprecated Epic Link in Cloud and replaced it with parent. Old saved filters still work, but you can't create new ones with Epic Link.

TO GET EPIC + ALL ITS STORIES + THEIR SUBTASKS

Cloud:

CLOUD
parent = PROJ-123 OR parentEpic = PROJ-123

Data Center:

DATA CENTER
"Epic Link" = PROJ-123 OR parent IN (issueFunction in issuesInEpics("key = PROJ-123"))

(Requires ScriptRunner for the subtasks part)

Copy-Paste Queries

Personal Work

PERSONAL QUERIES
-- Everything assigned to me (open)
assignee = currentUser() AND resolution IS EMPTY

-- My issues in current sprint
assignee = currentUser() AND sprint IN openSprints()

-- Where I'm mentioned (last 7 days)
(text ~ currentUser() OR comment ~ currentUser()) AND updated >= -7d

-- Issues I'm watching
watcher = currentUser() AND resolution IS EMPTY

-- Reported by me, still open
reporter = currentUser() AND resolution IS EMPTY

Dates and Deadlines

DATE QUERIES
-- Overdue
duedate < now() AND resolution IS EMPTY

-- Due this week
duedate >= startOfWeek() AND duedate <= endOfWeek()

-- Created today
created >= startOfDay()

-- Updated in last 24 hours
updated >= -24h

-- Created more than 30 days ago, still open
created <= -30d AND resolution IS EMPTY

-- Resolved last month
resolved >= startOfMonth(-1) AND resolved <= endOfMonth(-1)

-- No activity in 90 days
updated <= -90d AND resolution IS EMPTY

Status History

STATUS HISTORY
-- Was ever In Progress
status WAS "In Progress"

-- Currently Done, was In Progress at some point
status = "Done" AND status WAS "In Progress"

-- Status changed in the last 7 days
status CHANGED AFTER -7d

-- Moved to Done this week
status CHANGED TO "Done" AFTER startOfWeek()

-- Reopened issues (was resolved, now not)
status WAS IN ("Resolved", "Done", "Closed") AND resolution IS EMPTY

Sprint and Backlog

SPRINT QUERIES
-- Current sprint
sprint IN openSprints()

-- Current sprint, specific project
sprint IN openSprints() AND project = "PROJ"

-- Backlog (not in any active/future sprint)
(sprint IS EMPTY OR sprint NOT IN (openSprints(), futureSprints())) 
AND resolution IS EMPTY AND project = "PROJ"

-- Completed in closed sprints (not carried over)
sprint IN closedSprints() AND sprint NOT IN openSprints() AND resolution IS NOT EMPTY

-- Added to sprint mid-sprint (requires status history)
sprint IN openSprints() AND NOT status WAS "To Do" ON startOfWeek()

Team Queries

TEAM FILTERS
-- All issues for a group
assignee IN membersOf("dev-team")

-- Unassigned in project
project = "PROJ" AND assignee IS EMPTY AND resolution IS EMPTY

-- Created by my team this month
reporter IN membersOf("dev-team") AND created >= startOfMonth()

-- High priority without assignee
priority IN (Highest, High) AND assignee IS EMPTY AND resolution IS EMPTY

Epic and Hierarchy

Cloud:

CLOUD EPIC QUERIES
-- All issues in an Epic
parent = PROJ-123

-- Issues without an Epic
parent IS EMPTY AND issuetype != Epic AND issuetype NOT IN subtaskIssueTypes()

-- All Epics without children
issuetype = Epic AND NOT parent = *

Data Center:

DATA CENTER EPIC QUERIES
-- All issues in an Epic
"Epic Link" = PROJ-123

-- Issues without an Epic
"Epic Link" IS EMPTY AND issuetype != Epic AND issuetype NOT IN subtaskIssueTypes()

-- Subtasks of a specific parent
parent = PROJ-456

Text Search

TEXT SEARCH
-- Word in summary
summary ~ "migration"

-- Exact phrase
summary ~ "\"database migration\""

-- In summary OR description
summary ~ "error" OR description ~ "error"

-- In comments only
comment ~ "workaround"

-- Multiple words (AND logic)
text ~ "deployment production failed"

-- Wildcard (words starting with)
summary ~ "API*"

Filters and Cleanup

CLEANUP QUERIES
-- Issues with attachments
attachments IS NOT EMPTY

-- Issues without components
component IS EMPTY AND project = "PROJ"

-- Flagged/impediment
flagged = Yes

-- Exclude subtasks from results
issuetype NOT IN subtaskIssueTypes()

-- Issues with external links
issueLink IS NOT EMPTY

-- Specific link type
issueLinkType = "blocks"

Date Functions Reference

Function Returns Example
now() Current time (milliseconds) updated > now() - 1h
startOfDay() Today 00:00 created >= startOfDay()
endOfDay() Today 23:59:59 duedate <= endOfDay()
startOfWeek() Sunday 00:00 created >= startOfWeek()
endOfWeek() Saturday 23:59 duedate <= endOfWeek()
startOfMonth() 1st of month created >= startOfMonth()
endOfMonth() Last day of month duedate <= endOfMonth()
startOfYear() January 1 created >= startOfYear()
endOfYear() December 31 duedate <= endOfYear()

Offsets

All functions accept offset parameters:

OFFSET EXAMPLES
startOfDay("-1d")      -- Yesterday 00:00
startOfDay("+1d")      -- Tomorrow 00:00
startOfWeek("-1w")     -- Last week
startOfMonth("-1M")    -- Last month
startOfWeek("+1d")     -- Monday (workaround for Sunday default)

Relative Dates

RELATIVE DATES
-7d                    -- 7 days ago
-2w                    -- 2 weeks ago  
-1M                    -- 1 month ago
-1y                    -- 1 year ago

-- Combine with comparison:
created >= -7d         -- Created in last 7 days
updated <= -30d        -- Not updated in 30 days

Absolute Dates

ABSOLUTE DATES
created >= "2024-01-15"
created >= "2024-01-15 14:30"

Cloud vs Data Center Differences

Feature Cloud Data Center
Epic queries parent = EPIC-123 "Epic Link" = EPIC-123
parentEpic function ✅ Works ❌ Not available
WAS/CHANGED reliability ⚠️ Buggy in team-managed ✅ Stable
issueFunction (ScriptRunner) ❌ Not available ✅ With ScriptRunner
portfolioChildIssuesOf ✅ Built-in ✅ With Advanced Roadmaps

Everything else — operators, date functions, text search — works identically.

Performance Tips

1. Always Add Project When Possible

PERFORMANCE
-- Slower (scans everything):
status = "Open"

-- Faster (scoped to project):
project = "PROJ" AND status = "Open"

2. Use Specific Fields Instead of text

PERFORMANCE
-- Slow (searches all text fields):
text ~ "deployment"

-- Faster (searches specific fields):
summary ~ "deployment" OR description ~ "deployment"

3. IN Is Faster Than OR Chains

PERFORMANCE
-- Better:
status IN ("Open", "In Progress", "Review")

-- Worse:
status = "Open" OR status = "In Progress" OR status = "Review"

4. Avoid Leading Wildcards

PERFORMANCE
-- Forbidden and would be slow anyway:
summary ~ "*error"

-- OK:
summary ~ "error*"

5. ORDER BY Indexed Fields

PERFORMANCE
-- Fast:
ORDER BY created DESC

-- Potentially slow:
ORDER BY "Custom Text Field" ASC

Known Bugs Worth Knowing

Bug Description Status
JRASERVER-23030 != excludes empty values Won't Fix
JRASERVER-25092 Special character escaping doesn't work Won't Fix
JRACLOUD-72180 WAS/CHANGED unreliable in team-managed projects Open
JRACLOUD-70567 startOfWeek() ignores locale Closed (partial fix)
JRASERVER-63292 Request: CHANGED on more fields Gathering Interest

Quick Reference Card

Operators:

OPERATORS
=    !=    >    >=    <    <=
IN   NOT IN
~    !~    (text contains / doesn't contain)
IS   IS NOT   (for EMPTY/NULL)
WAS   WAS NOT   WAS IN   WAS NOT IN
CHANGED

Keywords:

KEYWORDS
AND   OR   NOT   ORDER BY
EMPTY   NULL   (synonyms)

Current User:

USER FUNCTIONS
currentUser()              -- Logged-in user
membersOf("group-name")    -- All users in group

Useful Issue Type Filters:

ISSUE TYPES
issuetype = Bug
issuetype IN standardIssueTypes()
issuetype IN subtaskIssueTypes()
issuetype NOT IN subtaskIssueTypes()

Useful Resources

Bookmark This Page

You'll be back. Everyone comes back for startOfWeek() syntax at least three times before it sticks.

JQL is powerful once you know the gotchas. These queries save hours every week when you stop fighting the syntax and start copying what works.

Next time you're stuck on a query, Ctrl+F this page. It's faster than the official docs.


Last updated: December 2025
Found this useful? It's part of our work at Votazz where we build tools for Jira administrators.

Scroll to Top