Feature: server-side pagination (:page) for result tables — let users page through the full result set
- Dominant language
- Clojure
- Stars
- 49.3k
- Forks
- 6.8k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 653
Description
**What problem will this feature request solve?**
Metabase currently returns only the first window of result rows (capped at a 2000-row `HARD_ROW_LIMIT`), with no way to fetch what comes after. For detail/explore workflows on large tables — auditing individual records, scanning a list, picking up where a previous view left off — users get cut off after the first 2000 rows and have no way to page further into the result set. This has surfaced as repeated support tickets asking for "the rest of the rows."
The backend has had full support for server-side pagination for years (the `:page` MBQL clause compiles to SQL `LIMIT`/`OFFSET`, with schema, Lib helpers, QP middleware, and driver support all in place). What's missing is purely the frontend: the query-builder UI and the table controls to drive it.
**Describe the solution you'd like.**
Expose the existing `:page` capability in the query builder so users can navigate pages of a result set:
1. **Lib JS/TS wrappers** — mark `current-page` and `with-page` as `^:export` in `metabase.lib.page`, and add a `currentPage`/`page` TypeScript wrapper (`frontend/src/metabase-lib/query/page.ts`) mirroring the existing `limit.ts`.
2. **Result table pagination** — add a page-size selector + prev/next (and jump-to-page) controls to the result table visualization, fetching the next window via the `:page` clause (server-side `OFFSET`), rather than a single fixed 2000-row window.
3. **(Optional, smaller)** A `PageStep` notebook step mirroring `LimitStep`, so page size is first-class in the notebook alongside the existing limit step.
`:page` is mutually exclusive with `:limit`, so the UI should replace (not combine with) the limit control when paging is active, matching the existing backend semantics.
**How does this feature request impact you?**
It unblocks detail/record-list workflows that currently dead-end at 2000 rows, and closes recurring support requests. The backend is already implemented and tested; the work is frontend wiring plus a small UI — low risk, bounded scope.
**Additional information**
- Backend proof-of-concept already present: `metabase.lib.page` (`current-page`, `with-page`), the `::page` schema in `metabase.lib.schema`, QP handling in `metabase.query-processor.middleware.limit` / `add-rows-truncated`, and SQL compilation in `metabase.driver.sql.query-processor`.
- The `LimitStep` notebook step + `LimitPopover` / `QuestionRowCount` are the templates to mirror for the UI.
- Relevant context: `:page` is a long-standing MBQL feature; compatibility with legacy MBQL 4 is moot since it is being phased out.
Contributor guide
Research direction
Start with metabase.lib.page and frontend/src/metabase-lib/query/page.ts, comparing the requested wrappers with limit.ts. Then inspect the LimitStep, LimitPopover, and QuestionRowCount templates and the result table controls. Done means users can select a page size, move between result pages, and jump to a page using :page without combining it with :limit.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- clojure, typescript
- Domain
- data-visualization, frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100