# Should a paginated API return an exact total count?

> Choose exact, estimated, cached, or omitted totals from the user action, cost, and freshness requirements. Separate counting from page retrieval and label approximation explicitly.

Canonical URL: https://www.devobs.io/articles/qa-exact-total-count/
By: Nina Patel
Published: 2023-08-08T13:17:55.136Z
Updated: 2026-09-06T08:31:04.426Z
Section: Architecture

Return an exact total count only when the client genuinely needs the exact number to decide what to do next. For routine list navigation, prefer an estimated or cached count, and omit counts entirely when `nextPageToken` is enough. Treat counting as separate work from fetching one page, and make the response say whether a count is exact or approximate.

## Does every paginated API need a total count?

No. A paginated API needs a reliable way to continue or stop [pagination](https://www.devobs.io/articles/pagination-under-concurrent-writes/) first. [Google AIP-158](https://google.aip.dev/158) says `next_page_token` is the way to communicate end of collection, and that responses *may* include `total_size`. It also says that total *“may be an estimate”* if the API documents that clearly.

That is the right default contract for many APIs. If the user is just moving through pages, an exact total often adds cost without changing behavior. Infinite scroll, event feeds, and admin tables with simple next/previous navigation usually work well with no total at all.

## When is an exact count worth the cost?

Use an exact count when the exact number changes the user action now: exporting all rows under a hard cap, showing “select all 437 items,” or displaying a legally meaningful total.

The reason to be selective is that exact counting is its own operation. [PostgreSQL aggregate documentation](https://www.postgresql.org/docs/current/functions-aggregate.html) defines `count(*)` as *“Computes the number of input rows.”* That is straightforward, but it is still separate work from retrieving a single page. A page query can be cheap with a good access path while a full exact count remains expensive.

If you promise exact totals, do not hide that work inside normal page retrieval. Measure and budget count latency separately.

## When should you return an estimate instead?

Return an estimate when users need scale, not precision: deciding whether to refine a search, understanding list size, or comparing “hundreds” versus “tens of thousands.”

PostgreSQL’s planner statistics are a useful model for this tradeoff. [PostgreSQL planner statistics](https://www.postgresql.org/docs/current/planner-stats.html) says `reltuples` values are *“not updated on-the-fly”* and *“usually contain somewhat out-of-date values.”* That is acceptable for estimates, as long as the API labels them honestly.

A practical response shape is:

```json
{
  "items": [{"id": "p_101"}, {"id": "p_102"}],
  "nextPageToken": "page_2",
  "count": {
    "value": 12480,
    "accuracy": "estimated",
    "asOf": "2026-09-05T19:45:00Z"
  }
}
```

Prerequisite: your backend must be able to produce page tokens without waiting for recounts. If not, the count path and page path are still coupled too tightly.

## What contract should you ship?

Use this checklist:

- Return `exact` when the workflow depends on the exact number now.
- Return `estimated` or cached when rough size is enough.
- Omit `count` when navigation only needs `nextPageToken`.
- Include metadata such as `accuracy` and `asOf` for any non-exact count.
- Offer an opt-in like `includeTotal=exact|estimated|none` if different clients have different needs.

One important limit: do not enforce business rules with a preflight count alone. If a write depends on “must remain under 10,000 items,” the enforced ordering boundary is the write path that accepts or rejects the change. A separate earlier `GET` can inform the UI, but it cannot guarantee correctness once concurrent writes exist.

### Follow-up Q&A

**Should only the first page include a count?**  
Yes, if that is documented. The count is often most useful when entering the list, not on every page fetch.

**Should estimated totals be rounded?**  
Often yes. If the purpose is scale, returning `12500` with `accuracy: estimated` is clearer than implying false precision.

Next step: pick one high-traffic [list endpoint](https://www.devobs.io/articles/permission-aware-list-endpoints/), measure page latency and count latency independently, then update the API contract to make count accuracy explicit before promising exact totals.

Reviewed: 2026-09-05

## Source references

- <https://google.aip.dev/158>
- <https://www.postgresql.org/docs/current/functions-aggregate.html>
- <https://www.postgresql.org/docs/current/planner-stats.html>
