Query language
A query is a line of text that says which things to show and how: assignee:me is:open sort:due is your open tasks, soonest due first. The same language runs
every query bar in the app:
- Tasks - the Tasks page, every saved view, a project's, milestone's or label's tasks, and a doc's live task lists.
- Dashboards - the filters every chart shares.
- Search (⌘K / CtrlK) - across every kind, see Searching across kinds.
- The hubs - Projects, Milestones, Docs, Views and Dashboards.
- Activity, the Shared links list, a form's rules and a Database.
- Outside the app - the REST API and AI tools.
This page covers task queries first, then what's different elsewhere.
#The query bar
In a task view, the query bar (f q) holds the whole view as text: filters, layout, grouping, sorting and display. Changing the chips updates the text and the other way round. It suggests fields and values as you type, applies the query as soon as it's complete, and says under the bar what it can't read, such as a field it doesn't know.
Its suggestions look like the filter chips' menus: a task shows its status, key, title, priority, project and type, a person their avatar, a Space its icon, and a status, priority, type or label its color, so two tasks with the same title are easy to tell apart. A project, milestone, Space or person shows its key on the right, and a label its folder.
They're in the same order as a filter chip's menu, too: the value the cursor is
in comes first, ticked, then unset and any, then everything else, with a
line between each part. Once you start typing, the best match comes first
instead, so Enter picks it.
Wherever a new clause can start - as soon as you click or Tab into the bar, or after a space that ends a clause - the list of fields opens, so you can see what you can filter by without knowing the names. Nothing in it is picked until you press the arrows, so Enter still runs the query; Escape closes the list.
A query is a list of field:value clauses separated by spaces. Words without
a field match task names and keys.
#How a clause is written
Every field is written the same way: lowercase, with a dash between words
(started-before:, blocked-by:). A field of the task itself is plain
(status:, due:); a field of something the task is linked to is the
kind, a dot, then the field (milestone.target:, project.name:).
project: on its own is the project, by its key - short for project.key:.
Every kind has a .key and a .name. task. in front of a field is the
task's own, so task.status: is status:. The same form is used across
the app, on the Activity page and in the hubs' query bars.
You can also type or paste a query into search (⌘K / CtrlK), which shows its clauses as chips and suggests as you type, like this bar: Open as query opens it in a Query tab, and Save as view saves it as a new view. Search also finds projects, docs, milestones and the rest by their fields - see Searching across kinds.
#Filters
| Field | Also accepts | Matches tasks… |
|---|---|---|
status: | state: | in that status |
priority: | p: | with that priority |
type: | tasktype: | of that type |
label: | labels:, tag:, tags: | with that label (any of the ones listed) |
assignee: | assigned:, owner: | assigned to that person |
mentions: | mention: | that mention that person |
project: | project.key: | in that project |
milestone: | milestone.key:, ms: | in that milestone (by key or name) |
space: | space.key: | kept in that Space (by key or name); space:unset is the workspace-wide ones |
parent: | parent.key:, subtaskof: | that are direct sub-tasks of that task |
root: | root.key: | that are that task, or reachable from it through sub-tasks and Blocks / Blocked by links (Related links don't count) |
task: | task.key:, id: | that are that exact task |
blocks: | blocksTaskKey: | that block that task; blocks:any blocks something, blocks:unset blocks nothing |
blocked-by: | blockedByTaskKey:, blockedby: | that are blocked by that task; blocked-by:any has a blocker (finished or not), blocked-by:unset has none, and blocked-by:open is still waiting on a blocker that's neither completed nor canceled (see Stuck work) |
related: | relatedTaskKey: | related to that task; related:any has a related task, related:unset has none |
child: | children: | that have that task as a sub-task; child:any has sub-tasks, child:unset has none |
estimate: | with that estimate: estimate:5, more or less (estimate:>3, estimate:<=2) or a range (estimate:3..8, both ends included); estimate:unset has none. When the workspace's estimates are time, a number is hours, as when you type an estimate, and a length of time works too: estimate:>2h, estimate:30m..1d, estimate:1h30m (a day is 8 hours) | |
comments: | with that many comments, compared the same way: comments:>5, comments:any has some, comments:unset has none | |
creator: | created-by:, author: | made by that person: creator:me is the ones you made |
comment.by: | commenter: | that person has commented on: comment.by:me |
follower: | followers:, followed-by: | that person follows: follower:me is the ones you follow, follower:unset the ones no one follows |
due: / start: | due / starting on that day | |
created: / updated: / completed: | created / last updated / completed on that day | |
started: | started on that day: when it first moved into a started status (started:unset is never started) | |
name: | task.name:, title:, text:, search: | whose title or key contains the text |
description: | desc: | whose description contains the text: description:"cat scan" |
internal: | internal:yes is internal tasks, hidden from guests; internal:no is the rest | |
project.name: | project.title: | whose project's name contains the text |
milestone.name: | milestone.title: | whose milestone's name contains the text |
space.name: | space.title: | whose Space's name contains the text |
label.name: | label.title: | with a label whose name contains the text |
assignee.name: | assignee.title: | assigned to someone whose name or email contains the text |
project.folder: | whose project is in that folder, or a folder inside it - see Folders | |
milestone.folder: | whose milestone is in that folder, or a folder inside it | |
label.folder: | with a label in that folder, or a folder inside it | |
custom.<name>: | by one of your custom fields: custom.points:>3, custom.client:Acme | |
checklist: | checklists: | by their checklists: any (has one), unset (has none), open (something left to tick), done (every item ticked), or a checklist's name - checklist:"After deploy" has something left to tick in a list of that name |
kind:task says what a query finds, and every query bar starts with it as a
chip with a lock, since it can't be edited: kind:task in Tasks and on
dashboards, kind:activity on the Activity page, kind:project in the
Projects hub. Typing it changes nothing; any other kind is an error. kind: is what comes
back, while project: only narrows it: kind:task project:P-0003 is the
tasks in that project, not the project.
A page that always shows part of the workspace shows that part locked after
kind:task, inside the same locked chip, the same as its locked filter chips: project:P-0003 on a
project's page, milestone:R-0046 on a milestone's, and space:S-0002 when
it's kept in a Space (a saved view or dashboard in a Space too). They can't
be removed and aren't saved with the query. Inside a Space, the filter menus
and the bar's suggestions offer only that Space's projects and milestones,
since another Space's could never match.
The names the bar wrote before still work and mean what they did -
projectKey:, taskParentKey:, taskRootKey:, taskKey:, taskTitle:,
blocksTaskKey:, blockedByTaskKey:, relatedTaskKey:, taskStarted: and
milestoneTarget: and the like - so saved views, dashboards and links keep
working. When the bar writes a query out, it uses the names above.
#Folders
project.folder:, milestone.folder: and label.folder: find tasks by the
hub folder their project, milestone or labels are filed in. Write a folder as
its path, top folder first, with / between the levels, in quotes when it has
spaces: project.folder:"Plan Things Better / Web". The spaces around /
don't matter, and neither does case.
- A folder takes in everything inside it, however deep:
project.folder:"Plan Things Better"finds the tasks of every project in that folder and in the folders inside it. -cuts a branch out:project.folder:"Plan Things Better" -project.folder:"Plan Things Better / Obsidian"leaves out the Obsidian folder and everything inside it.- A folder's name alone finds every folder with that name, at any depth:
project.folder:Webfinds bothPlan Things Better / WebandAbundant Life / Web. The suggestions show each folder's full path, so picking one writes the path that finds just it. unsetandany:project.folder:unsetis tasks whose project isn't in a folder, or that have no project;project.folder:anyis tasks whose project is in one.
They're also in the Filter menu, as Project folder, Milestone folder and Label folder, each once that hub has a folder (and Milestone folder once there are milestones). Each lists the hub's folders by their full path, then No folder; picking a folder takes in the ones inside it, as in a query.
The folder: of projects, milestones, docs, views, dashboards and labels, in
their hubs' query bars and in search, works the same way.
#Stuck work
blocked-by:open finds tasks still waiting on unfinished work: at least one
task blocking them is neither completed nor canceled (an archived blocker
counts as finished). A task whose blockers
are all done or canceled doesn't match, though blocked-by:any still does.
-blocked-by:open is the other way round: nothing left to wait on. Add
is:open to leave out tasks that are finished themselves:
is:open blocked-by:open sort:due.
#Combining and excluding
- Several values - separate them with commas:
status:Todo,"In Progress"matches either. Different fields must all match. A field written twice is the same as one with both values:-status:Done -status:Canceledis-status:Done,Canceled, and the query bar merges them into one chip once the query runs. A custom field is the exception - each of its clauses has to match on its own. - Spaces in a name - put it in quotes:
project:"Website redesign". - Excluding - put
-before the field:-status:Donehides Done tasks,-root:T-0042hides that task and everything connected to it. - You -
memeans whoever is looking:assignee:me,mentions:me. - Not set, or set -
unsetmatches a task with no value (assignee:unset,due:unset), andanya task with one (project:any,custom.points:any). Every field that takes one takes the other, and-turns one into the other:-project:anyis the same asproject:unset. Every task has a status, a creation date and a last change, sostatus:unset,created:unsetandupdated:unsetnever match, and the bar warns you. A custom field kept to some Spaces or task types counts only the tasks it applies to (more). - Has or holds - anything a task has is a field like the rest
(
project:any,checklist:open); there's nohas:, and the bar says which field to use instead (has:project→project:any).is:is only for the task as a whole:is:open,is:unscheduled,is:recurring. - Text that looks like a clause - put it in quotes:
"status:todo"searches titles for those words. - Exactly as stored - a value with an equals sign in front
(
label:="q3-launch") skipsme,unset,anyand name matching -label:=anyis a label named "any",checklist:=opena checklist named "open". The bar writes a value this way when it can't put a name to it.
Tasks, projects, milestones and Spaces are named by their key
(parent:T-0042, project:P-0003, space:S-0002), which is how the bar
writes them. A project's, milestone's or Space's name works too
(project:Website, space:"Client work"); if two share a name, the bar says
so - use the key.
Labels are written by name. The suggestions show the folder each label is in, and when two labels share a name, picking one writes it by its id, so the query finds just that one.
#Dates
Every date clause takes a day, written YYYY-MM-DD, or words for one that
move with the calendar:
- A day near today:
today,yesterday,tomorrow, or today moved by days, weeks, months or years:today-28d(28 days ago),today+2w,today-1m,today+1y. - A stretch of days:
this-week,last-week,next-week, the same formonth,quarterandyear(last-month,this-year), andlast-7-days,next-30-daysand the like. Weeks run Monday to Sunday. - A range: two of either with
..between them, both ends included:due:2026-10-01..2026-10-31,created:today-7d..today.
A word is saved as you wrote it, so a view or dashboard of
due-before:today shows what's past due every day, without being changed.
It's read by the date where you are (your profile's time zone), and an open
view moves on by itself at midnight. A shared link reads it by the date of
whoever made the link.
On a stretch of days, due:this-week is a day in it, due-before:this-week
is before its first day and due-after:this-week after its last.
While you type, the suggestions offer these words with the days they mean
beside them, and a date typed the way your workspace writes dates becomes
that day. The Filter menu's date filters offer the same words as quick
picks beside the calendar, and Filter → Overdue is is:overdue.
| Clause | Matches tasks… |
|---|---|
due-before: / due-after: | due before / after that day (not including it) |
start-before: / start-after: | starting before / after that day |
created-before: / created-after: | created before / after that day |
updated-before: / updated-after: | last updated before / after that day |
started-before: / started-after: | started before / after that day |
completed-before: / completed-after: | completed before / after that day |
The same words work for a task's milestone and project dates (below),
date custom fields
(custom.follow-up:<today), the Activity page's activity.after: and
activity.before:, and the dates in every hub and in search.
#Milestone and project dates
A task can be found by its milestone's or project's dates too: tasks in
milestones due this month, or in projects made before the summer. Each takes
a day, unset (no milestone or project, or that date isn't set on it) or
any, and has a -before: and -after: form, like the task's own dates:
milestone.target-before:2026-11-01. They're also in Filter → Milestone dates
and Filter → Project dates.
| Clause | Matches tasks whose… |
|---|---|
milestone.start: | milestone starts that day |
milestone.target: | milestone is due that day |
milestone.completed: | milestone was completed that day |
milestone.created: / milestone.updated: | milestone was made / last changed that day |
project.created: / project.updated: | project was made / last changed that day |
#Open, unscheduled and archived
| Clause | Matches tasks… |
|---|---|
is:open | whose status isn't in the Completed or Canceled category |
is:unscheduled | with no start or due date |
is:overdue | that are open and due before today - the same as due-before:today is:open |
is:recurring | that repeat |
show:archived | including archived tasks (include: works too) |
show:archived-only | only archived tasks |
show:recurring | Calendar and Timeline: upcoming repeats too, like Show upcoming repeats |
#Layout and display
| Clause | Values |
|---|---|
layout: | list, board, timeline, calendar, canvas, graph |
group: | none, status, priority, type, assignee, project, milestone, label, space, or a custom field that's a choice, choices or a person (group:custom.client) |
sort: | rank (manual), name, id, priority, status, due, start, estimate, created, updated, started (never-started tasks last), completed (when it was finished; never-finished tasks last: sort:-completed lists the last ones finished), type, project, milestone, assignee, labels, progress, relations, comments, subtasks, or a custom field (custom.points) - put - first for descending: sort:-due |
subtasks: | nested, flat, hidden |
empty: | show-normal, auto-collapse, auto-hide (or show, collapse, hide) - what empty groups or columns do |
hide: | properties to hide: type, project, milestone, priority, assignee, labels, estimate, start, due, progress, relations, checklists, or a custom field (custom.points) |
zoom: | Timeline: day, week, month, quarter, year, all |
calendar: | Calendar: month, week, 2weeks, 4weeks, schedule |
date: | Calendar: which date places a task - due, start, created, updated, completed, or two for a span: date:start,due |
canvas-layout: | Canvas: flow or tree |
canvas-direction: | Canvas: right or down |
relations: | Canvas: kinds of line to hide - blocks, parent, related |
The query bar always shows layout:, group: and sort:, even when nothing is filtered, so you can see which layout you're in. Pick another layout and its layout: takes the old one's place. A query without layout: shows a list.
#Examples
| Query | Shows |
|---|---|
assignee:me is:open sort:due | Your open tasks, soonest due first |
label:Bug -status:Done group:priority | Unfinished bugs, grouped by priority |
project:"Website redesign" layout:board | One project as a board |
due-before:2026-11-01 is:open layout:calendar | Open work due before November, on a calendar |
is:overdue sort:due | Everything past due, oldest first - every day |
creator:me created:this-week | What you've made this week |
estimate:>5 -estimate:unset | Big tasks, by their estimate |
root:T-0042 layout:canvas | A task and everything connected to it, as a graph |
project:P-0003 layout:graph | One project's tasks on the Graph |
#Searching across kinds
Search (⌘K / CtrlK) reads the same language, across everything it finds: tasks, projects, milestones, docs, views, dashboards, Spaces, chat channels, labels, templates and members. Templates show for people who can use them, as on the Templates page.
kind:picks what comes back:kind:project,doc. The chip beside the search box shows it - All kinds without one - and picking kinds there writeskind:for you.- A plain field is each item's own:
status:todofinds tasks and projects in Todo,status:draftdocs in Draft. Something without that field (a label has no status) doesn't match. {kind}.{field}is that kind's field, and finds those items and everything linked to them:project.name:websitefinds the Website project, its tasks and the docs attached to it.{kind}:on its own is that item by key or name:project:P-0003,space:"Client work".- Words beside them narrow it by name, as in any search:
kind:doc owner:me brief. They match an item's description (or a member's email) too.
| Kind | Its own fields |
|---|---|
| Every kind | key, name, created, updated |
| Task | status, priority, type, label, assignee, project, milestone, space, parent, due, start, started, completed, archived |
| Project | status, space, folder |
| Milestone | state (status works too), space, folder, start, target, completed |
| Doc | status, type, owner, space, folder, shared, project, milestone, task |
| View | layout, owner, space, folder, shared |
| Dashboard | owner, space, folder, shared |
| Label | color, folder |
| Space | visibility |
| Channel | space |
| Template | owner |
| Member | email, role, status |
Dates take a day, words like today or this-week (see
Dates), unset or any, with -before and -after
(project.created-after:2026-09-01). A query that's also a task query
(status:todo) still offers Open as query for its tasks.
#Other query bars
Every other query bar is written the same way - field:value, commas for
several values, - to exclude, unset and any, quotes around spaces - with
fields of its own. Each one suggests them as you type.
- Activity -
activity.by:,activity.action:,activity.kind:,activity.field:,activity.to:,activity.from:,activity.after:andactivity.before:, alongside the task filters above. - Projects, Milestones and Docs - each hub's page lists its fields.
- Shared links - who made a link, its name and what it shares, its access and status, and its dates.
- A form's rules - the form's questions as fields.
#Databases
A Database's views take a query written with the table's own column names:
each column's name in lower case, with a dash for each space. A table with
Status, Due date and Owner columns reads
status:Doing due-date:<today owner:me sort:-due-date group:status.
| Column | Values |
|---|---|
| Text and links | words the cell contains |
| Numbers | 5, >5, <=5, or a range: 3..8 |
| Dates | the same, as days (2026-11-01, <2026-11-01) or words (today) |
| Selects | an option's name; several, separated by commas, match any |
| People | me, a member's key, name or email |
| Checkboxes | yes or no |
| Any column | any (or set) and unset |
sort: takes a column (- first for descending), group: a column, and -
in front of a column excludes. Words without a field search every cell.