Swiftpack.co - Package - nodes-vapor/paginator

Paginator ๐Ÿ—‚

Swift Version Vapor Version Circle CI codebeat badge codecov Readme Score GitHub license

GIF of paginator

This package currently offers support for offset pagination on Array and QueryBuilder.

๐Ÿ“ฆ Installation

Add Paginator to the package dependencies (in your Package.swift file):

dependencies: [
    .package(url: "https://github.com/nodes-vapor/paginator.git", from: "3.0.0-rc")

as well as to your target (e.g. "App"):

targets: [
        name: "App",
        dependencies: [... "Paginator" ...]

Next, copy/paste the Resources/Views/Paginator folder into your project in order to be able to use the provided Leaf tags. These files can be changed as explained in the Leaf Tags section, however it's recommended to copy this folder to your project anyway. This makes it easier for you to keep track of updates and your project will work if you decide later on to not use your own customized leaf files.

Getting started ๐Ÿš€

First make sure that you've imported Paginator everywhere it's needed:

import Paginator

Adding the Leaf tag

In order to do pagination in Leaf, please make sure to add the Leaf tag:

public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
    services.register { _ -> LeafTagConfig in
        var tags = LeafTagConfig.default()
            "offsetPaginator": OffsetPaginatorTag(templatePath: "Paginator/offsetpaginator")

        return tags

If you want to fully customize the way the pagination control are being generated, you are free to override the template path.


To return a paginated result from QueryBuilder, you can do the following:

router.get("galaxies") { (req: Request) -> Future<OffsetPaginator<Galaxy>> in
    return Galaxy.query(on: req).paginate(on: req)


For convenience, Paginator also comes with support for paginating Array:

router.get("galaxies") { (req: Request) -> Future<OffsetPaginator<Galaxy>> in
    let galaxies = [Galaxy(), Galaxy(), Galaxy()]
    return galaxies.paginate(on: req)

Leaf tags

To use Paginator together with Leaf, you can do the following:

router.get("galaxies") { (req: Request) -> Response in
    let paginator: Future<OffsetPaginator<Galaxy>> = Galaxy.query(on: req).paginate(on: req)
    return paginator.flatMap(to: Response.self) { paginator in
        return try req.view().render(
            GalaxyList(galaxies: paginator.data ?? []), 
            userInfo: try paginator.userInfo()
        .encode(for: req)

Please note how the Paginator data is being passed in using userInfo on the render call. Forgetting to pass this in will result in an error being thrown.

Then in your MyLeafFile.leaf you could do something like:

    #for(galaxy in galaxies) {


Calling the Leaf tag for OffsetPaginator will automatically generate the Bootstrap 4 HTML for showing the pagination controls:

<nav class="paginator">
    <ul class="pagination justify-content-center table-responsive">
        <li class="page-item">
            <a href="/admin/users?page=16" class="page-link" rel="prev" aria-label="Previous">
                <span aria-hidden="true">ยซ</span>
                <span class="sr-only">Previous</span>
        <li class="page-item "><a href="/admin/users?page=1" class="page-link">1</a></li>
        <li class="disabled page-item"><a href="#" class="page-link">...</a></li>
        <li class="page-item "><a href="" class="page-link">12</a></li>
        <li class="page-item "><a href="" class="page-link">13</a></li>
        <li class="page-item "><a href="" class="page-link">14</a></li>
        <li class="page-item "><a href="" class="page-link">15</a></li>
        <li class="page-item "><a href="" class="page-link">16</a></li>
        <li class="page-item  active "><a href="" class="page-link">17</a></li>
        <li class="page-item "><a href="/admin/users?page=18" class="page-link">18</a></li>
        <li class="page-item">
            <a href="/admin/users?page=18" class="page-link" rel="next" aria-label="Next">
                <span aria-hidden="true">ยป</span>
                <span class="sr-only">Next</span>


The OffsetPaginator has a configuration file (OffsetPaginatorConfig) that can be overwritten if needed. This can be done in configure.swift:

public func configure(_ config: inout Config, _ env: inout Environment, _ services: inout Services) throws {
    // ..
        perPage: 1,
        defaultPage: 1

๐Ÿ† Credits

This package is developed and maintained by the Vapor team at Nodes. The package owner for this project is Siemen.

๐Ÿ“„ License

This package is open-sourced software licensed under the MIT license


Stars: 38
Help us keep the lights on


3.0.0 - Dec 4, 2018


  • This package now correctly pins towards Swift 4.1 in Package.swift (thanks @cb1674).

3.0.0-rc.1 - Oct 29, 2018


  • Leaf tag that generates Bootstrap HTML controls for paginating views.

3.0.0-beta.2 - Sep 6, 2018


  • Support for overwriting the count when using the OffsetPaginator on QueryBuilder. This is helpful in cases where you're doing complex queries and you need to control how the count is being calculated.
  • Support for overwriting the count when using the OffsetPaginator on arrays.


  • Instead of having to make a paginator for then to transform its content, you can now transform your content (coming from an array or a QueryBuilder) before calling paginate. This removes the need for the intermediate instance for defining the type of the (first) paginator.

โš ๏ธ This is a breaking release

3.0.0-beta.1 - Aug 27, 2018


  • Rewritten for Vapor 3 ๐ŸŽ‰

2.0.0 - Nov 8, 2017


  • Statically configure paginator key