<p>
    Pagination is the process of dividing data into discrete pages. In Appwrite, it is achieved by using an offset or a cursor, which both come with their own use case and benefits.
</p>

<h2><a href="/docs/pagination#offset-pagination" id="offset-pagination">Offset Pagination</a></h2>
<p>
    Using <code>Query.limit()</code> and <code>Query.offset()</code> you can achieve one of the most common approaches to pagination.
    With <code>Query.limit()</code> you can define to how many documents that can be returned from one request.
    The <code>Query.offset()</code> is simply the number of records you wish to skip before selecting records.
</p>

<ul class="phases clear" data-ui-phases>
    <li>
        <h3>Web</h3>
        <div class="ide" data-lang="javascript" data-lang-label="Web SDK">
            <pre class="line-numbers"><code class="prism language-javascript" data-prism>import { Client, Databases, Query } from "appwrite";

const client = new Client()
    .setEndpoint('https://cloud.appwrite.io/v1')
    .setProject('[PROJECT_ID]');

const databases = new Databases(client);
                
// Page 1
const page1 = await databases.listDocuments(
    '[DATABASE_ID]',
    '[COLLECTION_ID]',
    [
        Query.limit(25),
        Query.offset(0)
    ]
);

// Page 2
const page2 = await databases.listDocuments(
    '[DATABASE_ID]',
    '[COLLECTION_ID]',
    [
        Query.limit(25),
        Query.offset(25)
    ]
);</code></pre>
        </div>
    </li>
    <li>
        <h3>Flutter</h3>
        <div class="ide" data-lang="javascript" data-lang-label="Flutter SDK">
        <pre class="line-numbers"><code class="prism language-dart" data-prism>import 'package:appwrite/appwrite.dart';

void main() async {
    final client = Client()
        .setEndpoint('https://cloud.appwrite.io/v1')
        .setProject('[PROJECT_ID]');

    final databases = Databases(client);

    final page1 = await databases.listDocuments(
        databaseId: '[DATABASE_ID]',
        collectionId: '[COLLECTION_ID]',
        queries: [
            Query.limit(25),
            Query.offset(0)
        ]
    );

    final page2 = await databases.listDocuments(
        databaseId: '[DATABASE_ID]',
        collectionId: '[COLLECTION_ID]',
        queries: [
            Query.limit(25),
            Query.offset(25)
        ]
    );
}
</code></pre>
        </div>
    </li>
    <li>
        <h3>Android</h3>
        <div class="ide" data-lang="kotlin" data-lang-label="Android SDK">
            <pre class="line-numbers"><code class="prism language-kotlin" data-prism>import io.appwrite.Client
import io.appwrite.Query
import io.appwrite.services.Databases

suspend fun main() {
    val client = Client(applicationContext)
        .setEndpoint("https://cloud.appwrite.io/v1")
        .setProject("[PROJECT_ID]")

    val databases = Databases(client)

    val page1 = databases.listDocuments(
        databaseId = "[DATABASE_ID]",
        collectionId = "[COLLECTION_ID]",
        queries = [
            Query.limit(25),
            Query.offset(0)
        ]
    )

    val page2 = databases.listDocuments(
        databaseId = "[DATABASE_ID]",
        collectionId = "[COLLECTION_ID]",
        queries = [
            Query.limit(25),
            Query.offset(25)
        ]
    )
}</code></pre>
        </div>
    </li>
    <li>
        <h3>Apple</h3>
        <div class="ide" data-lang="swift" data-lang-label="Apple SDK">
            <pre class="line-numbers"><code class="prism language-swift" data-prism>import Appwrite
import AppwriteModels

func main() async throws {
    let client = Client()
        .setEndpoint("https://cloud.appwrite.io/v1")
        .setProject("[PROJECT_ID]")

    let databases = Databases(client)

    let page1 = try await databases.listDocuments(
        databaseId: "[DATABASE_ID]",
        collectionId: "[COLLECTION_ID]",
        queries: [
            Query.limit(25),
            Query.offset(0)
        ]
    )

    let page2 = try await databases.listDocuments(
        databaseId: "[DATABASE_ID]",
        collectionId: "[COLLECTION_ID]",
        queries: [
            Query.limit(25),
            Query.offset(25)
        ]
    )
}</code></pre>
        </div>
    </li>
</ul>

<p>
    The request gets slower as the number of records increases because the database has to read up to the offset number of rows to know where it should start selecting data.
    Also when there is data added in high frequency - the individual pages might skip results.
</p>

<h2><a href="/docs/pagination#cursor-pagination" id="cursor-pagination">Cursor Pagination</a></h2>
<p>
    The cursor is a unique identifier for a document that points to where the next page should start. After reading a page of documents, pass the last document's ID into the <code>Query.cursorAfter(lastId)</code> query method to get the next page of documents. Pass the first document's ID into the <code>Query.cursorBefore(firstId)</code> query method to retrieve the previous page.
</p>

<ul class="phases clear" data-ui-phases>
    <li>
        <h3>Web</h3>
        <div class="ide" data-lang="javascript" data-lang-label="Web SDK">
            <pre class="line-numbers"><code class="prism language-javascript" data-prism>import { Databases, Query } from "appwrite";

const client = new Client()
    .setEndpoint("https://cloud.appwrite.io/v1")
    .setProject("[PROJECT_ID]");

const databases = new Databases(client);

// Page 1
const page1 = await databases.listDocuments(
    '[DATABASE_ID]',
    '[COLLECTION_ID]',
    [
        Query.limit(25),
    ]
);

const lastId = page1.documents[page1.documents.length - 1].$id;

// Page 2
const page2 = await databases.listDocuments(
    '[DATABASE_ID]',
    '[COLLECTION_ID]',
    [
        Query.limit(25),
        Query.cursorAfter(lastId),
    ]
);</code></pre>
        </div>
    </li>
    <li>
        <h3>Flutter</h3>
        <div class="ide" data-lang="javascript" data-lang-label="Flutter SDK">
        <pre class="line-numbers"><code class="prism language-dart" data-prism>import 'package:appwrite/appwrite.dart';

void main() async {
    final client = Client()
        .setEndpoint('https://cloud.appwrite.io/v1')
        .setProject('[PROJECT_ID]');

    final databases = Databases(client);

    final page1 = await databases.listDocuments(
        databaseId: '[DATABASE_ID]',
        collectionId: '[COLLECTION_ID]',
        queries: [
            Query.limit(25)
        ]
    );

    final lastId = page1.documents[page1.documents.length - 1].$id;

    final page2 = await databases.listDocuments(
        databaseId: '[DATABASE_ID]',
        collectionId: '[COLLECTION_ID]',
        queries: [
            Query.limit(25),
            Query.cursorAfter(lastId)
        ]
    );

}
</code></pre>
        </div>
    </li>
    <li>
        <h3>Android</h3>
        <div class="ide" data-lang="kotlin" data-lang-label="Android SDK">
            <pre class="line-numbers"><code class="prism language-kotlin" data-prism>import android.util.Log
import io.appwrite.AppwriteException
import io.appwrite.Client
import io.appwrite.Query
import io.appwrite.services.Databases

suspend fun main() {
    val client = Client(applicationContext)
        .setEndpoint("https://cloud.appwrite.io/v1")
        .setProject("[PROJECT_ID]")

    val databases = Databases(client)

    val page1 = databases.listDocuments(
        databaseId = "[DATABASE_ID]",
        collectionId = "[COLLECTION_ID]",
        queries = [
            Query.limit(25)
        ]
    )

    val lastId = page1.documents[page1.documents.size - 1].$id

    val page2 = databases.listDocuments(
        databaseId = "[DATABASE_ID]",
        collectionId = "[COLLECTION_ID]",
        queries = [
            Query.limit(25),
            Query.cursorAfter(lastId)
        ]
    )
}</code></pre>
        </div>
    </li>
    <li>
        <h3>Apple</h3>
        <div class="ide" data-lang="swift" data-lang-label="Apple SDK">
            <pre class="line-numbers"><code class="prism language-swift" data-prism>import Appwrite
import AppwriteModels

func main() async throws {
    let client = Client()
      .setEndpoint("https://cloud.appwrite.io/v1")
      .setProject("[PROJECT_ID]")

    let databases = Databases(client)

    let page1 = try await databases.listDocuments(
        databaseId: "[DATABASE_ID]",
        collectionId: "[COLLECTION_ID]",
        queries: [
            Query.limit(25)
        ]
    )

    let lastId = page1.documents[page1.documents.count - 1].$id

    let page2 = try await databases.listDocuments(
        databaseId: "[DATABASE_ID]",
        collectionId: "[COLLECTION_ID]",
        queries: [
            Query.limit(25),
            Query.cursorAfter(lastId)
        ]
    )
}</code></pre>
        </div>
    </li>
</ul>

<h2><a href="/docs/pagination#when-to-use-what" id="when-to-use-what">When to use what?</a></h2>
<p>
    The different scenarios in which offset or cursor pagination make the most sense depends on the data itself and how often new records are added.
    When querying static data, the performance cost alone may not be enough for you to use a cursor, as the added complexity that comes with it may be more than you need.
</p>
<p>
    <b>Offset pagination</b> should be used for static data with an indicator to what is the current page and how many pages are available in total. For example a list with up to 20 pages or static data like a list of countries or currencies.
</p>
<p>
    <b>Cursor pagination</b> should be used high-frequency data which is lazy-loaded with infinite scrolling. For example a feed, comment section, chat history or high volume datasets.
</p>