Skip to content

Instantly share code, notes, and snippets.

@isDipesh
Last active December 18, 2025 13:06
Show Gist options
  • Select an option

  • Save isDipesh/fdfd5197e89447a9ed6ee48338fe3f5f to your computer and use it in GitHub Desktop.

Select an option

Save isDipesh/fdfd5197e89447a9ed6ee48338fe3f5f to your computer and use it in GitHub Desktop.
Drizzle Query Pagination Util for Nitro/Nuxt
import type { H3Event } from 'h3'
import { count } from 'drizzle-orm'
const DEFAULT_PAGE_SIZE = 20
const MAX_PAGE_SIZE = 200
type PaginateableQuery<TQuery> = {
limit: (limit: number | undefined) => PaginateableQuery<TQuery>
offset: (offset: number | undefined) => PaginateableQuery<TQuery>
orderBy: (orderBy: string) => PaginateableQuery<TQuery>
}
type Pagination = {
page: number
size: number
count: number
pages: number
}
export async function paginateResults<TQuery>(
query: TQuery,
event: H3Event,
) {
const queryParams = getQuery(event)
const page = queryParams.page ? parseInt(queryParams.page as string) : 1
const paginationConfig = useRuntimeConfig().public.pagination
let size = Number(queryParams.size ?? (paginationConfig && typeof paginationConfig === 'object' && 'defaultSize' in paginationConfig && typeof paginationConfig.defaultSize === 'number' ? paginationConfig.defaultSize : DEFAULT_PAGE_SIZE))
const maxSize = paginationConfig && typeof paginationConfig === 'object' && 'maxSize' in paginationConfig && typeof paginationConfig.maxSize === 'number' ? Number(paginationConfig.maxSize) : MAX_PAGE_SIZE
if (size > maxSize) {
size = maxSize
}
const offset = (page - 1) * size
const results = await (query as PaginateableQuery<TQuery>)
.limit(size)
.offset(offset)
// @ts-expect-error - config is available in runtime but not in type
query.config.fields = { resultCount: count() }
const [{ resultCount }] = await (query as PaginateableQuery<TQuery>).limit(undefined).offset(undefined).orderBy('1') as unknown as { resultCount: number }[]
const pages = Math.ceil(resultCount / size)
if (page > pages) {
throw createError({
statusCode: 404,
statusMessage: 'Page not found',
})
}
return {
results: results as unknown as Awaited<Promise<TQuery>>,
pagination: {
page,
size,
count: resultCount,
pages,
} as Pagination,
}
}
@isDipesh
Copy link
Author

isDipesh commented Dec 17, 2025

Usage example:

const query = db.select().from(users)
const response = await paginateResults(query, event)

Request:

GET /api/users?page=2&size=5

Response:

{
  "results": [
    {
      "id": 6,
      "name": "Sarah Connor",
      "email": "[email protected]",
      "role": "admin"
    },
    {
      "id": 7,
      "name": "Kyle Reese",
      "email": "[email protected]",
      "role": "user"
    },
    {
      "id": 8,
      "name": "Rick Deckard",
      "email": "[email protected]",
      "role": "user"
    },
    {
      "id": 9,
      "name": "Ellen Ripley",
      "email": "[email protected]",
      "role": "manager"
    },
    {
      "id": 10,
      "name": "Marty McFly",
      "email": "[email protected]",
      "role": "user"
    }
  ],
  "pagination": {
    "page": 2,
    "size": 5,
    "count": 52,
    "pages": 11
  }
}

Framework-agnostic Drizzle Pagination util:
https://gist.github.com/isDipesh/1b3aa2851bb59b053a1b67f38db806e0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment