"Blocks" and "is blocked by" are two of the most useful link types in Jira — used well, they let you model real dependencies between work items. They also share one big flaw: they're invisible until you're already looking at the item. Nothing shows up on a board, backlog, or filter to say "this can't move forward yet" or "three other items are waiting on this one." Teams either end up training everyone to check the Links panel on every card (doesn't scale) or bolt on a marketplace app just to surface something Jira already knows.
I wanted a way to make blocking relationships visible at a glance, using only native Jira Automation — no app, no added cost, and no manual upkeep. Here's the approach I landed on, generalized so you can drop it into your own instance.
When a "Blocks" link is created, prefix the blocking item's summary with [BLOCKER] and the blocked item's summary with [BLOCKED] (plus a Dependent label for filtering) — then automatically remove those tags the moment they stop being true, whether that's because the link is deleted or because the dependency resolves itself.
Example: Link work item A ("Build API endpoint") as a blocker of work item B ("Build UI that calls the endpoint"). After the link is created:
[BLOCKER] Build API endpoint[BLOCKED] Build UI that calls the endpoint (and B picks up a Dependent label)Anyone scanning the backlog or board now sees the dependency without opening either item. When A is completed, or someone removes the link, both tags disappear on their own — no one has to remember to clean them up.
| Rule | Trigger | Job |
|---|---|---|
| Set | A Blocks link is added |
Tag both sides of the new relationship |
| Clear on Unlink | A Blocks link is deleted |
Untag both sides, if nothing else still justifies the tag |
| Clear on Resolve | An item transitions to a "finished" status | Untag itself, and cascade the cleanup to anything still linked to it |
Trigger: Issue Link Added — link type Blocks Trigger condition: the triggering item's status isn't already closed (I exclude Done and Won't Do — use whatever your closed statuses are)
Logic:
[BLOCKER], and it isn't in a Done status category → set summary to [BLOCKER] {{issue.Summary}}[BLOCKED], and it isn't in a Done status category → set summary to [BLOCKED] {{issue.Summary}} and add the label DependentI also added a simple space-exclusion condition here — one area of my instance (a roadmap-style space) doesn't benefit from per-item summary prefixes, so I filtered it out of both branches. Easy to bolt on if you have something similar.
Trigger: Issue Link Deleted — link type Blocks
Logic:
Blocks relationship: if its summary still contains [BLOCKER], and it no longer has any remaining Blocks links → strip the [BLOCKER] prefix[BLOCKED], and it no longer has any remaining is blocked by links → strip [BLOCKED] and remove the Dependent labelThe important detail is "any remaining links," not "this specific link." If an item has three separate blockers and you remove one, it should stay tagged [BLOCKED] until all three are gone. Checking for the presence of any remaining link of that type — rather than just reacting to the one that was deleted — is what makes this safe for many-to-many blocking relationships.
One known limitation: if someone deletes the linked item itself rather than just removing the link, this rule can throw an error, even though the tag cleanup on the surviving item still completes correctly. I haven't found a clean way around it — Jira Automation doesn't currently offer a way to check "does the other end of this link still exist" — so I've accepted it as a cosmetic error in the audit log and moved on.
This one took the most iteration, because "the dependency resolved itself" has to account for every other active link that item might still have.
Trigger: Issue Transitioned Trigger condition (JQL): statusCategory = Done OR status = Verification — swap in whatever combination of statuses you treat as "finished" (I also treat a pre-close verification step the same as Done)
Logic:
SourceIssueKey = {{issue.key}} (needed below — see the first gotcha)[BLOCKER], strip it — a finished item can't meaningfully block anything[BLOCKED], strip it and remove the Dependent labelissue in linkedIssues({{issue.key}}, "is blocked by")AND statusCategory != Done AND status != VerificationAND Key != {{SourceIssueKey}}
If none match, and the item is still tagged [BLOCKED], clear the tag and the label.issue in linkedIssues({{issue.key}}, "blocks")AND statusCategory != Done AND status != VerificationAND Key != {{SourceIssueKey}}
If none match, and the item is still tagged [BLOCKER], clear the tag.A log action stating the source key and current status right after step 1 is optional, but it's cheap, and it pays for itself the first time you're staring at the automation audit log trying to figure out why a cascade branch didn't fire.
1. Exclude the source issue explicitly — don't rely on re-checking its status. Steps 4 and 5 both filter out the just-transitioned item by key rather than trusting a fresh JQL check of its status. That's deliberate. The condition runs moments after the transition, and JQL here is served from Jira's search index rather than the live field value — there's a small but real propagation delay. Without the Key != {{SourceIssueKey}} filter, the source item can briefly still show up as an "active blocker" in that search, and the cascade cleanup would incorrectly skip clearing the other item's tag. Capturing the key in a variable at the top of the rule and filtering it out downstream sidesteps the whole race condition. It's a good pattern to remember any time an automation rule needs to reason about the current item's post-change state from inside a related-issue JQL check.
2. Removing a link is not the same as deleting an issue. As noted above, deleting a linked item outright can produce a harmless but noisy error on the unlink rule. Worth knowing before you assume a red mark in the audit log means the tags are wrong — check the actual summary before digging further.
labels = Dependent) without parsing summary text.Blocks / is blocked by for whatever link type names you actually use if you've renamed or added custom link types[BLOCKER] / [BLOCKED] and Dependent are just what I landed onThe whole thing runs entirely on native Jira Cloud Automation — no marketplace app, no added license cost, and it fixes itself as work moves instead of relying on someone remembering to update a flag. If you build a version of this, I'd love to hear what you changed. And if you find an edge case I haven't — multi-hop blocking chains three or more levels deep are the one I'm still keeping an eye on — drop it in the comments.
Gary Spross
3 comments