Home Documentation Templates Examples Showcase GitHub ↗
Theme

Core reference · Multi-output generation

Pagination.

Pagination turns one tracked item into an ordered set of generated pages while keeping that set one dependency-aware build unit. Render @item blocks, place exactly one @paginate, and let Nift split the rendered items across pages.

Pagination stays inside Nift's existing model.

The tracked item owns the whole page set. Any relevant change rebuilds the complete set; Nift does not maintain a separate incremental graph for each pagination page. The resulting pages can still be rendered concurrently.

Enable pagination in tracked.json

{
  "name": "blog",
  "title": "Blog",
  "template": "templates/template.html",
  "paginate": {
    "items-per-page": 10
  }
}

items-per-page is required and must be a positive integer. A paginated item also needs a pagination template. If no explicit template path is configured, Nift derives the conventional sibling <content-stem>.paginate.html.

Reusable template and separator paths

"paginate": {
  "items-per-page": 10,
  "template": "templates/pagination/posts.html",
  "separator": "templates/pagination/post-separator.html"
}

An explicit path wins over the conventional sibling. When separator is omitted, Nift uses <content-stem>.separator.html if that file exists; otherwise items are concatenated without an inserted separator. Pagination templates and separators are ordinary rendered Nift source, so they may use metadata, @input, checked paths and other supported template features.

Collect items and place the result

@json('data/posts.json', posts)

@for(post : posts by post.date desc){
    @item{
        <article>
            <h2>$[post.title]</h2>
        </article>
    }
}

@paginate

@item{...} renders immediately while the current JSON/loop scope is active and captures that rendered fragment as one pagination item. Items may appear before or after @paginate. A paginated tracked item must execute exactly one @paginate; zero or multiple insertion points are build errors.

The pagination template

For content/blog.html, the conventional template is content/blog.paginate.html. It receives a small read-only pagination namespace:

<section class="posts">
    $[paginate.items]
</section>

<nav>
    @if(!paginate.first){
        <a href="@pathtopage($[paginate.previous])">Previous</a>
    }

    <span>Page $[paginate.current] of $[paginate.total]</span>

    @if(!paginate.last){
        <a href="@pathtopage($[paginate.next])">Next</a>
    }
</nav>
ValueMeaning
$[paginate.items]The rendered items selected for this page, joined with the rendered optional separator.
$[paginate.current]Current page number, one-based.
$[paginate.total]Total number of generated pagination pages.
$[paginate.first]true on the first page.
$[paginate.last]true on the last page.
$[paginate.previous]Previous page number; page 1 resolves to 1.
$[paginate.next]Next page number; the final page resolves to the final page number.

@pathtopage(n)

@pathtopage(n) is available while rendering pagination and requires n to resolve to an integer. An unsigned integer is an absolute page number; an explicit + or - makes the integer a relative offset from the current page. Expressions may supply that integer, but fractional values are invalid. The final resolved page number must remain between 1 and $[paginate.total].

@pathtopage(3)
@pathtopage($[paginate.previous])
@pathtopage(+1)
@pathtopage(-1)
@pathtopage(+$[offset])

Output naming

tracked name: blog
public/blog.html
public/blog-2.html
public/blog-3.html

tracked name: blog/
public/blog/index.html
public/blog/2.html
public/blog/3.html

The first pagination page remains the tracked item's normal primary output. Secondary outputs use deterministic names owned by that same tracked item.

Zero items and lifecycle

Zero items is valid. Nift still renders the primary page once; $[paginate.items] is empty, paginate.current/paginate.total are both 1, and first/last are both true.

If the number of pages shrinks, Nift removes stale secondary outputs owned by the previous successful pagination build. If pagination is disabled, old secondary pagination outputs are removed. Missing generated pagination outputs make the tracked item stale so the complete set can be regenerated.

Failure and concurrency semantics

Pagination pages may render concurrently, including a single tracked item that expands into thousands of outputs. Thread completion order does not define page order. Nift stages the new page set and preserves the previous successful set if the new pagination render fails rather than committing a mixture of old and new pages.

Dependencies and requirements discovered from content, items, the pagination template and separator form one conservative union owned by the tracked item. A change to any of them rebuilds the complete pagination set.