> ## Content Index
> Fetch the complete content index at: https://notionsolutions.net/llms.txt
> Use this file to discover other available public pages before exploring further.

# Notion Formula length(): Count Tasks, Tags, Words and Unique Values
- URL: https://notionsolutions.net/notion-formula-length-count/
- Published: 2026-10-30T10:17:17.000Z
- Updated: 2026-10-30T10:17:20.000Z
- Description: There's no count() in Notion's formula reference, so length() does the counting. Copy formulas for open and overdue tasks, percent done, distinct tags and names, characters and words, see what each returns for six sample tasks, and know when a rollup Count is the simpler choice.
- Author: Kevin Turner
- Tags: guide, databases

**To count in a Notion formula, use length(): it returns the number of characters in text or items in a list, so `prop("Tasks").length()` counts a project's related tasks. Notion's formula reference has no count() function, so to count only some items, filter the list and take its length.** I'd use a rollup Count for a plain total, because it needs no code, and a formula once the count needs a condition, a percentage or a case rule.

```
prop("Tasks").filter(current.prop("Status") != "Done").length()
```

That one line counts the open tasks on a project. The sections below cover what length() returns for each property type, conditional counts, percentages, distinct values, words, the rollup alternative and the mistakes behind a wrong number. The worked example near the end takes six sample tasks and works out every formula's result by hand, so you can compare your own preview against it.

## What length() counts for each property type

length() takes one value and returns a number. What that number means depends on the property you feed it, and Notion's [formula syntax reference](https://www.notion.com/help/formula-syntax?ref=notionsolutions.net) lists the type each property turns into inside a formula.

__What .length() returns for each property type__
| Property type | What .length() counts                                                            | Example                                              |
| ------------- | -------------------------------------------------------------------------------- | ---------------------------------------------------- |
| Title or Text | Characters, including spaces and punctuation                                     | prop("Title").length(); "Monkey D. Luffy" returns 15 |
| Multi-select  | Options selected on that page (a text list)                                      | prop("Tags").length()                                |
| Person        | People in the cell                                                               | prop("Upvoted by").length()                          |
| Relation      | Related pages (a page list)                                                      | prop("Tasks").length()                               |
| Rollup        | Depends on the rollup: a list counts its items, a number should be used as it is | prop("Purchases").length()                           |
| Number        | Digits, which is rarely what you want                                            | 12345.length() returns 5                             |

The Title, Multi-select, Relation and Rollup examples come from Notion's table, which says a rollup's type "depends on rollup configuration." The Person example is from Notion's guide to [formulas that extend what databases do](https://www.notion.com/help/guides/write-formulas-that-extend-capabilities-of-databases?ref=notionsolutions.net), where it adds up the people tagged in an Upvoted by column. Thomas Frank's [length() page](https://thomasjfrank.com/formulas/functions/length/?ref=notionsolutions.net) gives the 15 for "Monkey D. Luffy", and his [Formulas 2.0 cheat sheet](https://thomasjfrank.com/notion-formula-cheat-sheet/?ref=notionsolutions.net) notes that length() also accepts a number, with `12345.length()` returning 5\. That's why a rollup that already returns a number, say 12, gives 2 once you wrap it in length().

Notion's [intro to formulas](https://www.notion.com/help/formulas?ref=notionsolutions.net) uses the same function for a Tasks remaining property, `Tasks.length()`. As written, that counts every related task, finished or not; a filter is what turns it into a remaining count. Before formulas had lists, counting comma-separated items took a replaceAll() trick; Frank's cheat sheet keeps that old version and notes that lists make the job much simpler.

## Count only the items that match a condition

Every conditional count has the same shape: list, filter(), length(). Inside filter(), `current` stands for each item in turn, and `current.prop()` reads a property of that related page; the [prop() guide](https://notionsolutions.net/notion-formula-prop/) covers how those references work. The recipes below sit on a Projects database with a Tasks relation.

### Open tasks

```
prop("Tasks").filter(current.prop("Status") != "Done").length()
```

Notion's property table writes this filter with `!==`; its function list documents `!=` under unequal, which is the form used here. I'd count "not Done" rather than listing every open status, because a status you add later, such as Waiting on client, then counts as open without anyone editing the formula. The flip side is that a Cancelled status would count as open too, so add it to the condition if you use one.

### Overdue tasks

```
prop("Tasks").filter(
  !empty(current.prop("Due")) and
  current.prop("Due") < today() and
  current.prop("Status") != "Done"
).length()
```

today() returns the current date without the time, so with date-only Due values the strict `<` keeps a task due today out of the overdue count. The `!empty()` check means a task with no due date never counts as overdue. If the property shows a type error instead of a number, the [date error guide](https://notionsolutions.net/notion-formula-date-errors/) walks through the usual causes.

### Billable, tagged and upcoming

```
prop("Tasks").filter(current.prop("Billable")).length()
```

```
prop("Tasks").filter(current.prop("Tags").includes("Design")).length()
```

```
prop("Meetings").filter(current.prop("Date") > now()).length()
```

A checkbox already returns true or false, so it can be the whole condition. A multi-select is a list, so test it with includes(), the way Notion's syntax table does with `prop("Tags").includes("Finance")`; a single Select compares with `==`, as in `prop("Priority") == "High"`. For the meetings line, now() includes the current time and today() drops it, so pick the one that matches how your dates are entered.

## Turn two counts into a percentage

```
lets(
  total, prop("Tasks").length(),
  done, prop("Tasks").filter(current.prop("Status") == "Done").length(),
  if(total == 0, 0, round(done / total * 100))
)
```

lets() names each count once, so the formula reads like the sentence it stands for. The `if(total == 0, 0, …)` part matters on a new project. Notion's [Formulas 2.0 guide](https://www.notion.com/help/guides/new-formulas-whats-changed?ref=notionsolutions.net) builds a similar percentComplete value by dividing completed tasks by all tasks, with no check for a project that has no tasks yet, and that project would be dividing by zero.

round() with one argument gives a whole number; Notion's reference shows a second argument for decimal places, so `round(done / total * 100, 1)` keeps one decimal. I'd keep the result a number rather than gluing a % sign onto it, because a number can feed another formula, such as an ifs() that labels the project, while text would need converting back first. The [let() and lets() guide](https://notionsolutions.net/notion-formula-let/) explains the variable syntax, and the [if() and ifs() guide](https://notionsolutions.net/notion-formula-if-ifs/) covers turning the percentage into labels.

## Count distinct values

### Distinct tags across a project's tasks

```
prop("Tasks").map(current.prop("Tags")).flat().unique().length()
```

Read it left to right. map() collects each task's Tags, which gives a list of lists, one per task. flat() merges them into one list; Frank's [flat() page](https://thomasjfrank.com/formulas/functions/flat/?ref=notionsolutions.net) points out that Notion's version flattens only one level, and one level is all this needs. unique() drops the repeats and length() counts what's left. Leave out unique() and you get total tag uses instead. Frank also recommends the Show Details icon while you build list formulas, because it shows the data type and the brackets around list items, so you can see where each step stands.

### Distinct names typed by hand

```
prop("Tasks").map(current.prop("Requested by").lower()).unique().length()
```

unique() is case-sensitive, so Dana and dana count as two people. Frank's [unique() page](https://thomasjfrank.com/formulas/functions/unique/?ref=notionsolutions.net) handles that by mapping every item through lower() first, which turns "Zangief", "zangief" and "ZANGIEF" into one value. In this setup Requested by is a Text property. If stray spaces creep in, use `current.prop("Requested by").trim().lower()` inside the map, and see the [text-cleaning formulas](https://notionsolutions.net/notion-formula-capitalize-first-letter/) if you'd rather fix the stored names than only count them.

### Counting through two relations

```
prop("Projects").map(current.prop("Tasks")).flat().length()
```

From a Clients database, this counts every task on every project for that client. Formulas can reach into properties of related databases, and the same map-then-flat pattern turns the per-project task lists into one list, so you can still add a filter() before length() to count only open work. The rollup shortcut isn't available here: Notion's [relations and rollups help](https://www.notion.com/help/relations-and-rollups?ref=notionsolutions.net) answers "Can I rollup a rollup?" with "Unfortunately not." If one task is linked to two projects, it sits in both lists and is counted twice. For the clients, projects and tasks structure itself, the [client project tracker build](https://notionsolutions.net/notion-client-project-tracker-template/) sets up those relations.

[![Two Notion counting pipelines: a Tasks relation of 6 pages passes through filter(current.prop("Status") != "Done") to 4 pages and length() returns 4; the same 6 pages map to 6 tag lists, flat() gives 7 tags, unique() leaves Design, Copy, Dev and Admin, and length() returns 4](https://storage.ghost.io/c/5c/30/5c30c46b-86a3-4d20-984f-4f6ae8ad1ed2/content/images/2026/10/notion-formula-length-count-count-pipelines.webp)](https://storage.ghost.io/c/5c/30/5c30c46b-86a3-4d20-984f-4f6ae8ad1ed2/content/images/2026/10/notion-formula-length-count-count-pipelines.webp?ref=notionsolutions.net)

A conditional count filters first; a distinct count maps, flattens and removes repeats before length().

## Count characters and words in text

### Characters, and characters left

```
prop("Caption").length()
```

```
let(limit, 150, limit - prop("Caption").length())
```

The first returns the character count, spaces included. The second shows how many characters remain under a limit you choose; 150 is a placeholder for whatever the client's brief says, and a negative result means the text runs over.

### Words

```
prop("Notes").match("\\S+").length()
```

match() returns every match of a regular expression as a list. The pattern \\S+ matches each run of characters that isn't whitespace, and length() counts the runs. That's the word count I'd use, because double spaces, spaces at either end and line breaks don't change it. Notion's syntax reference writes regular expressions with a doubled backslash, as in `match("Notion 123 Notion 456", "\\d+")`, which returns \["123", "456"\]; Frank's [string reference](https://thomasjfrank.com/formulas/data-types/string/?ref=notionsolutions.net) lists `\\` as the escape for one backslash, which is why the doubled form reaches the regex as \\S+, and his [match() page](https://thomasjfrank.com/formulas/functions/match/?ref=notionsolutions.net) shows the single-backslash form returning the same matches. I copy Notion's doubled form. Open the formula editor from a row that has text, and its live preview shows the count for that row before you save.

```
prop("Notes").trim().split(" ").filter(current != "").length()
```

If you'd rather avoid regular expressions, this version trims the ends, splits on spaces and drops the empty pieces that double spaces leave behind. It splits only on spaces, so two words separated by a line break count as one.

An older approach counts spaces instead. Notionthings' 2022 [word count formula](https://notionthings.com/2022/01/13/word-count-page-count-functions/?ref=notionsolutions.net) removes every character that isn't a space, takes the length of what remains and adds 1, which it describes as counting "the spaces between words." That holds on tidy text, but each extra space adds a word: in the test table below it gives 5 for a four-word line with a double space.

[![The phrase Send the revised quote with a double space after the, its four words numbered, and three word counts: match("\\S+").length() returns 4, trim().split(" ").filter(current != "").length() returns 4, and counting spaces plus 1 returns 5, marked overcount](https://storage.ghost.io/c/5c/30/5c30c46b-86a3-4d20-984f-4f6ae8ad1ed2/content/images/2026/10/notion-formula-length-count-word-counts.webp)](https://storage.ghost.io/c/5c/30/5c30c46b-86a3-4d20-984f-4f6ae8ad1ed2/content/images/2026/10/notion-formula-length-count-word-counts.webp?ref=notionsolutions.net)

A double space adds a word only when the formula counts spaces.

For the body of a page, skip the formula. Notion's [writing and editing basics](https://www.notion.com/help/writing-and-editing-basics?ref=notionsolutions.net) says that when you select one or more blocks, the menu shows how many words and characters are in the selection, and the ••• menu at the top right of the page shows the count for the whole page. Use that for drafts and long notes, and a formula for text that lives in a property.

## Rollup Count or formula: which one to use

A rollup is the no-code option. Notion's [rollup setup](https://www.notion.com/help/relations-and-rollups?ref=notionsolutions.net) asks for the relation, a property of the related pages, the calculation, the number formatting and the decimal places, with no step for a condition. Here's what each count calculation does according to that help page, and a formula that gets the same kind of number.

__Rollup count calculations and their formula equivalents__
| Rollup calculation               | What Notion's help says it counts                                         | Formula for the same kind of number                                                            |
| -------------------------------- | ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| Count all                        | The total number of values in the selected property for all related pages | prop("Tasks").length(), which matches when the property holds one value per page, such as Name |
| Count values                     | Non-empty values in the selected property                                 | prop("Tasks").filter(!empty(current.prop("Due"))).length()                                     |
| Count unique values              | Unique values in the selected property                                    | prop("Tasks").map(current.prop("Requested by")).unique().length()                              |
| Count empty                      | Related pages with an empty value for the property                        | prop("Tasks").filter(empty(current.prop("Due"))).length()                                      |
| Count not empty                  | Related pages with assigned values for the property                       | Same as Count values on a single-value property like Due                                       |
| Percent empty, Percent not empty | The percentage of related pages with no value, or with a value            | The lets() percentage above, with empty() or !empty() as the condition                         |

Because none of these takes a condition, "tasks not Done" or "billable tasks" can't come from a rollup count alone; that's the point where I switch to a formula. For a plain total on a project page, I'd still pick the rollup, since a teammate can open it and see exactly what it counts without reading code. Rollups can only be sorted when they output a number, and every count calculation does. The wording also differs: Count values counts values, while Count not empty counts pages. On a single-value property like Due they match; on a multi-select like Tags they may not, so check either one against a project you can count by eye. If a rollup shows the wrong number, the [rollup troubleshooting guide](https://notionsolutions.net/notion-rollup-not-working/) starts with empty and missing relations, and the [relations and rollups walkthrough](https://notionsolutions.net/notion-relations-and-rollups/) covers the setup.

## Why a count comes out wrong

__Wrong counts, their usual cause and the fix__
| What you see                                        | Usual cause                                                                                                | Fix                                                                                              |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| The count includes finished tasks                   | length() runs on the whole relation                                                                        | Add filter() before length()                                                                     |
| A rollup count wrapped in length() reads 1 or 2     | length() on a number counts its digits                                                                     | Use the rollup's number directly                                                                 |
| An older formula counts characters instead of items | The 2.0 update converted formulas that referenced rollup, person, file and multi-select properties to text | Remove the conversion part, such as .map(current.format()).join(", "), so length() sees the list |
| A multi-select condition never matches              | \== compares the whole list with one option                                                                | Use includes("Option")                                                                           |
| Duplicate names survive unique()                    | unique() is case-sensitive                                                                                 | Map through lower() first                                                                        |
| The distinct-tag count looks like a task count      | flat() is missing, so the list still holds one tag list per task                                           | Add flat() after map()                                                                           |
| The percentage breaks on a project with no tasks    | The formula divides by a total of 0                                                                        | Guard it with if(total == 0, 0, …)                                                               |
| An error after chaining formulas and rollups        | Each reference to another formula or rollup adds a layer, and the limit is 15                              | Count from the relation in one formula                                                           |
| The word count is too high                          | The formula counts spaces, so extra spaces add words                                                       | Use match("\\\\S+")                                                                              |

Notion's guide to [common formula errors](https://www.notion.com/help/common-formula-errors?ref=notionsolutions.net) sets the depth rule: formulas "can only be 15 layers deep," every reference to another formula or rollup adds a layer even across databases, and the fix is to combine formulas and rollups into fewer properties. A single filter().length() on the relation is one property where a rollup feeding a formula feeding another formula is three. The same guide tells automation formulas to use .includes instead of == for a multi-select condition. For migrated formulas, Notion's Formulas 2.0 guide says you'll need to remove the conversion language to get the list back, and the [Formulas 2.0 fix guide](https://notionsolutions.net/notion-formulas-2-0/) shows how to spot it in a copied template.

## Test results: six sample tasks, every count worked by hand

Here's one sample project, Site launch, with six related tasks. Assume today() returns March 10 and every Due date falls in the same year. Status, Due, Billable (checkbox), Tags (multi-select) and Requested by (text) are properties of the Tasks database. Each result below follows from the function definitions in Notion's syntax reference, with the tasks behind it listed so you can recount.

__The six tasks related to the Site launch project__
| Task                     | Status      | Due    | Billable | Tags        | Requested by |
| ------------------------ | ----------- | ------ | -------- | ----------- | ------------ |
| 1\. Draft sitemap        | Done        | Mar 3  | Yes      | Design      | Dana         |
| 2\. Write homepage copy  | Done        | Mar 6  | Yes      | Copy        | dana         |
| 3\. Build contact form   | In progress | Mar 9  | Yes      | Dev, Design | Lee          |
| 4\. Review mobile layout | Not started | Mar 8  | No       | Design      | Dana         |
| 5\. Set up analytics     | Not started | Mar 12 | Yes      | Dev         | Priya        |
| 6\. Collect client logos | Not started | Empty  | No       | Admin       | Lee          |

__What each count returns for the Site launch project__
| Count                      | Result | How it gets there                                                              | Rollup that matches                                           |
| -------------------------- | ------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------- |
| All tasks                  | 6      | Six related pages                                                              | Count all on Name: 6                                          |
| Open (Status != "Done")    | 4      | Tasks 3, 4, 5 and 6                                                            | None, it needs a condition                                    |
| Overdue                    | 2      | Tasks 3 (Mar 9) and 4 (Mar 8); 1 and 2 are Done, 5 is due later, 6 has no date | None                                                          |
| Billable                   | 4      | Tasks 1, 2, 3 and 5                                                            | None                                                          |
| Tagged Design              | 3      | Tasks 1, 3 and 4                                                               | None                                                          |
| Percent done               | 33     | 2 of 6 is 33.33, rounded to a whole number                                     | None; Percent not empty measures filled-in values, not status |
| Tag uses, without unique() | 7      | 1 + 1 + 2 + 1 + 1 + 1                                                          | Check Count values on Tags against 7                          |
| Distinct tags              | 4      | Design, Copy, Dev, Admin                                                       | Check Count unique values on Tags against 4                   |
| Requesters as typed        | 4      | Dana, dana, Lee, Priya                                                         | Check Count unique values on Requested by against 4           |
| Requesters after lower()   | 3      | dana, lee, priya                                                               | None                                                          |
| Tasks with a Due date      | 5      | Every task except 6                                                            | Count values or Count not empty on Due: 5                     |
| Tasks without a Due date   | 1      | Task 6                                                                         | Count empty on Due: 1                                         |
| Due date coverage          | 83     | 5 of 6 is 83.33, rounded                                                       | Percent not empty on Due, shown with the decimals you set     |

The coverage row reuses the percentage formula with `!empty(current.prop("Due"))` as the condition. Three rollup cells say "check" because Notion's help defines Count unique values as the number of unique values without saying whether Dana and dana are one value or how a multi-select's tags are counted. That's the useful test: build the rollup next to the formula on one project like this and see whether the two agree.

Text formulas get the same treatment. Each row is a value in a Notes text property; spaces and line breaks are described in words, since a web page would hide them.

__Character and word counts for six Notes values__
| Notes value                                         | Characters (length) | Words (match) | Words (trim, split, filter) | Words (counting spaces) |
| --------------------------------------------------- | ------------------- | ------------- | --------------------------- | ----------------------- |
| Empty                                               | 0                   | 0             | 0                           | 0                       |
| Invoice                                             | 7                   | 1             | 1                           | 1                       |
| Send the revised quote, with two spaces after "the" | 23                  | 4             | 4                           | 5                       |
| Send quote, with one space before and one after     | 12                  | 2             | 2                           | 4                       |
| Call Dana, then a line break, then Send quote       | 20                  | 4             | 3                           | 3                       |
| Logo v2 - approved!                                 | 19                  | 4             | 4                           | 4                       |

In the 20, the line break counts as one character. The hyphen in the last row counts as a word under every method, because each one splits on spaces or whitespace. The space-counting formula returns 0 for the empty value only because Notionthings wraps it in an if() that checks the length first. Only match() gives the same count however the spaces and line breaks fall, which is why it's the one I'd put in a Notes database.

## Verdict: rollup for plain totals, filter().length() for anything with a rule

For a plain total, use a rollup Count. For a count with a condition, use filter().length(); for a percentage, two counts in lets() with a zero guard; for distinct values, map(), flat(), unique() and lower(); for words, match(). Start with the open-task count on one project you can count by eye, and copy the pattern to other properties once the preview matches. The formula counts whatever passes the filter. Deciding what "open" or "billable" means for your client work is still your call, and that decision is the condition you write once.

## Questions that come up next

### How do I add up numbers instead of counting them?

Map the list to a number property and end with sum() instead of length(). Frank's [map() page](https://thomasjfrank.com/formulas/functions/map/?ref=notionsolutions.net) totals time-tracking sessions with `prop("Sessions").map(current.prop("Duration")).sum()`, and a Sum rollup does the same without a condition. If a total doesn't match the linked records, the [rollup sum guide](https://notionsolutions.net/notion-rollup-sum-wrong/) reconciles it.

### How do I count the days between two dates?

That's dateBetween(), not length(). Notion's example, `dateBetween(prop("Birthday"), now(), "days")`, returns the difference in the unit you name, from years down to minutes. If the result is one day off, the [dateBetween off-by-one guide](https://notionsolutions.net/notion-datebetween-off-by-one/) explains why.

### Can Notion AI write a counting formula for me?

On Business and Enterprise plans, Notion AI can create and edit formulas and show a preview of the output. I'd still check its count against a project small enough to count by hand, because the AI writes the filter but you're the one who knows which tasks should pass it.