Jira JQL: = and IN on Text Fields Are Switching to Exact Phrase Search

TL;DR

Atlassian announced on 6 October 2026 (CHANGE-3440) that =, IN and NOT IN on text fields now run an exact phrase search instead of a full-value match. Atlassian’s example: textField = "urgent" matches “urgent”, “urgent issue” and “very urgent issue”, not only a field whose whole value is “urgent”.

  • = and IN get broader: filters, gadgets and automation rules can return more issues.
  • NOT IN gets narrower: it drops every issue whose text contains the phrase.
  • You can preview the results today: Atlassian defines the new = as the same search as ~ with escaped quotes, textField ~ "\"urgent\"".

Not live yet on the two Cloud sites we checked (6 October 2026): on Epic Name, which accepts =, the operator still compared the whole value, and Summary and other standard text fields still reject =. The results below come from the equivalent ~ query, run against 12 demo work items on one test site.

What exactly changed

The operator stops comparing the whole value and looks for the phrase anywhere inside it. Atlassian’s rules, as published:

Rule Per Atlassian, after CHANGE-3440
Match scope The phrase may appear anywhere in the text; before, the whole value had to be equal
textField = "urgent" Matches “urgent”, “urgent issue” and “very urgent issue”
Several words Same words, same order, next to each other: "alpha beta" matches “prefix alpha beta suffix”, not “beta alpha” or “alpha something beta”
Case Insensitive
Stemming Still applies: “run” may match “running” (our test below disagrees)
IN ("alpha beta", "urgent") Matches either phrase anywhere in the text
NOT IN (…) Follows from the above: excludes items that contain any of the phrases

Phrase matching returns 3 of 5 summaries for "urgent issue", whole-value matching 1

The left panel applies the old whole-value rule as Atlassian describes it; Summary itself never accepted =. The right panel is what summary ~ "\"urgent issue\"" returned on our test site.

Which fields does this touch? The notice does not list them. On both sites we checked, Jira still rejects =, !=, IN and NOT IN on Summary, Description, Environment, Comment and Short text / Paragraph custom fields (“The operator ‘=’ is not supported by the ‘summary’ field”), and refuses to save a filter with that JQL. Some string-valued fields already accept = and IN, for example URL fields and some Atlassian- or app-provided fields. Audit both groups; the script below covers them.

Is it live yet? Not on our two sites as of 6 October 2026. The Epic Name field accepts both = and ~, so it shows which rule is active. = still compared the whole value on both sites:

Query on 6 Oct 2026 Old rule expects New rule expects Returned
"Epic Name" = "iOS Platform Update" the epic the epic the epic
"Epic Name" = "ios platform update" the epic the epic the epic
"Epic Name" = "Platform Update" nothing the epic nothing
"Epic Name" ~ "\"Platform Update\"" the epic the epic the epic
"Epic Name" = "Dashboard" nothing 2 epics with “Dashboard” in the name nothing
"Epic Name" IN ("Dashboard", "Cloud") the “Cloud” epic 3 epics the “Cloud” epic

Run the third query against an Epic Name on your own site. If it starts returning the epic, the change has reached you.

Jira rejects = on Summary with a JQL error

Today, summary = "Urgent issue" is rejected in the issue search on our test site (6 Oct 2026).

Tested on a real Cloud site

We ran the ~ query that Atlassian says equals the new =. The results follow the published phrase rules, except that a quoted phrase did not stem. The 12 demo work items, labelled jql-phrase-demo, have these summaries: “Urgent”, “Urgent issue”, “Very urgent issue”, “URGENT ISSUE in production”, “Issue urgent”, “Urgent customer issue”, “Not urgent”, “Urgently needed: VPN access”, “Server running out of memory”, “Alpha beta release notes”, “Beta alpha rollback” and “Alpha build for beta testers”.

Each query was prefixed with labels = jql-phrase-demo AND:

Query we ran (works today) Equivalent new = / IN, per Atlassian Returned Not returned (notable)
summary ~ "\"urgent\"" summary = "urgent" 7: Urgent, Urgent issue, Very urgent issue, URGENT ISSUE in production, Issue urgent, Urgent customer issue, Not urgent Urgently needed: VPN access
summary ~ "\"urgent issue\"" summary = "urgent issue" 3: Urgent issue, Very urgent issue, URGENT ISSUE in production Issue urgent (order), Urgent customer issue (gap), Urgent
summary ~ "\"alpha beta\"" summary = "alpha beta" 1: Alpha beta release notes Beta alpha rollback, Alpha build for beta testers
summary ~ "alpha beta" none (words, no phrase) 3: all three alpha/beta items —
(summary ~ "\"urgent issue\"" OR summary ~ "\"alpha beta\"") summary IN ("urgent issue", "alpha beta") 4 —
summary !~ "\"urgent\"" summary NOT IN ("urgent") 5: the three alpha/beta items, Server running out of memory, Urgently needed 7 items, including Not urgent
summary ~ "\"run\"" summary = "run" 0 Server running out of memory
summary ~ "run" none (word search) 1: Server running out of memory —

Stemming: the notice says the new = equals ~ with escaped quotes, and also that it still stems. On our site those two statements conflict: the quoted ~ "\"run\"" found nothing, and only the unquoted ~ "run" found “running”. Atlassian’s phrase search article also says a phrase finds no word variations. Don’t rely on either behaviour until you can test = on your own site.

Phrase search for "urgent" returns seven work items

"urgent" as a phrase: every summary that contains the word, in any position and any case.

Phrase search for "urgent issue" returns three work items

"urgent issue": only the words together, in that order. “Issue urgent” and “Urgent customer issue” drop out.

Unquoted alpha beta matches the words in any order

Quoted "alpha beta" matches only the exact order

Without escaped quotes, ~ "alpha beta" finds the words in any order (3 items). With them, only “Alpha beta release notes” remains.

Where this bites

The riskiest places are the ones nobody looks at: rules and scripts that run unattended and act on whatever the query returns.

  • Saved filters, board filters, dashboard gadgets. An = or IN on a text value can return more items, so counts, charts and swimlanes grow. Shared filters change for everyone who uses them.
  • Automation rules. JQL conditions and “Lookup work items” actions that use = match more items, and the rule then edits, transitions or notifies all of them.
  • NOT IN used as an exclusion list. It stops hiding one exact value and hides every item that contains the phrase. The equivalent !~ query on our site also excluded “Not urgent” (screenshot below).
  • Scripts and apps that call the REST API. On our sites, POST /rest/api/3/search/jql answered HTTP 200 with an empty issues list for summary = "…", with no error or warning, while the issue search UI showed the error. A script that looks up summary = "<marker>" before creating an item therefore never finds it and creates a duplicate every time. If = starts phrase-matching on that field, the same lookup can instead return “Nightly build 2” for “Nightly build”. Validate generated JQL with POST /rest/api/3/jql/parse?validation=strict, and compare the returned value exactly in code.

NOT IN-style exclusion also drops "Not urgent"

The NOT IN ("urgent") equivalent keeps 5 of 12 items. “Not urgent” and every other item containing the word is excluded; “Urgently needed” stays, because a phrase does not match other word forms.

How to audit your site

Start with saved filters: gadgets, boards and some automation rules run on them. The script below lists every saved filter that uses =, !=, IN or NOT IN on a string-valued field, plus Summary and the other standard text fields as a safety net. It reads the field list from your own site, so app-provided fields are included.

  1. Open your Jira site in the browser as a user with the Administer Jira global permission. The script passes overrideSharePermissions=true, so it sees every filter, not only those shared with you.
  2. Open the developer console (F12 → Console), paste the script and press Enter.
  3. Review each row it prints: clause shows the field and operator, jql the full query. Expect some false positives: keyword-style string fields that accept = may not be affected.
// Paste into the browser console on https://<your-site>.atlassian.net
(async () => {
  const ac = await (await fetch('/rest/api/3/jql/autocompletedata')).json();
  const fields = ac.visibleFieldNames.filter(f =>
    (f.types || []).includes('java.lang.String') &&
    !f.value.endsWith('.property') &&
    f.operators.some(op => ['=', '!=', 'in', 'not in'].includes(op)));
  const names = new Set(['summary', 'description', 'environment', 'comment', 'text', 'textfields']);
  fields.forEach(f => {
    names.add(f.value.replace(/^"|"$/g, '').toLowerCase());
    if (f.cfid) names.add(f.cfid.toLowerCase());
  });
  const esc = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  const re = new RegExp('(?:^|[\\s(])"?(' + [...names].map(esc).join('|') +
    ')"?\\s*(!=|=|not\\s+in\\b|in\\b)', 'i');
  const hits = [];
  for (let startAt = 0, last = false; !last;) {
    const page = await (await fetch('/rest/api/3/filter/search?expand=jql,owner' +
      `&overrideSharePermissions=true&maxResults=100&startAt=${startAt}`)).json();
    page.values.forEach(f => {
      const m = (f.jql || '').match(re);
      if (m) hits.push({ id: f.id, name: f.name, owner: f.owner?.displayName,
                         clause: m[0].trim(), jql: f.jql });
    });
    last = page.isLast; startAt += page.maxResults;
  }
  console.table(hits);
  return hits;
})();

On our test site it flagged the one demo filter that uses "Project overview key" = "SK" and skipped the one that uses ~. It only calls GET endpoints.

Then cover what the script cannot see:

  • Automation: in Settings → System → Global automation, export your rules as JSON. Quotes inside JQL are escaped there, so search case-insensitively with a regex such as (=|!=|\bin\b|\bnot in\b) next to your text field names.
  • Your own scripts and apps: search the code for JQL that uses = or IN on text values, and validate it with the parse endpoint above.
  • Shared dashboards: note the counts on your busiest gadgets now, so you can compare once the change reaches your site.

Rewrite cheat sheet

Pick the operator by what you mean, not by habit. The first five rows ran on our test site exactly as written.

You want Write Note
The exact phrase, anywhere in the text summary ~ "\"urgent issue\"" Same result as the new =; works today
The words in any order (no phrase) summary ~ "alpha beta" Unquoted terms stem: ~ "run" found “running”
Any of several phrases (summary ~ "\"urgent issue\"" OR summary ~ "\"alpha beta\"") Same as the new IN
Exclude a phrase summary !~ "\"urgent\"" Same as the new NOT IN; also drops “Not urgent”
Words starting with a prefix summary ~ "urge*" Found 8 items, incl. “Urgently”; a leading * is rejected
The whole value and nothing else Not possible on Summary, Description, Environment, Comment, Short text or Paragraph fields Narrow with the phrase search, then compare the full value in an automation condition or in code

If you need exact matching on a value every time, store it in a field built for it: a select list, labels or a component.

FAQ

Do I have to change anything right now? Only if a filter, rule or script relies on =, IN or NOT IN returning whole-value matches on a text value. Run the audit, then rewrite with the cheat sheet so the intent is explicit.

Is ~ affected? The notice does not change it. ~ with and without escaped quotes is the reference Atlassian uses to describe the new =.

Sources

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.