Documentation
Infinite Queries
Use page numbers, offsets, or cursors with stable filters, cancellation, and safe infinite-query keys.
Infinite queries
Use toInfiniteQuery() for load-more buttons, infinite scrolling, and other paginated lists.
micro-rq does not choose how pagination works. getVariables converts TanStack Query's pageParam into the variables expected by your endpoint.
The helper returns queryKey, queryFn, and initialPageParam. Add getNextPageParam and other TanStack Query options at the hook call.
1const postsQuery = useInfiniteQuery({2 ...posts.list.toInfiniteQuery({3 initialPageParam: 0,4 keyVariables: {5 tag,6 limit: 20,7 },8 getVariables: ({ pageParam, keyVariables }) => ({9 skip: pageParam,10 ...keyVariables,11 }),12 }),13 getNextPageParam: (lastPage) => {14 const nextSkip = lastPage.skip + lastPage.limit;15 16 return nextSkip < lastPage.total ? nextSkip : undefined;17 },18});Page numbers, offsets, and cursors
pageParam is generic, so it can be a number, string, object, or null.
Only getVariables changes between pagination styles. The endpoint still owns URL and query serialization.
1// Page number2posts.list.toInfiniteQuery({3 initialPageParam: 1,4 getVariables: ({ pageParam }) => ({5 page: pageParam,6 limit: 20,7 }),8});1// Offset2posts.list.toInfiniteQuery({3 initialPageParam: 0,4 getVariables: ({ pageParam }) => ({5 skip: pageParam,6 limit: 20,7 }),8});1// Cursor2messages.list.toInfiniteQuery({3 initialPageParam: null as string | null,4 getVariables: ({ pageParam }) => ({5 cursor: pageParam,6 limit: 20,7 }),8});Filters and infinite query keys
Put every stable value that changes the complete list in keyVariables, such as search text, category, sort order, tenant, or page size.
getVariables receives the same keyVariables, which keeps the cache identity and HTTP request connected.
Do not put the changing page number, offset, or cursor in keyVariables. TanStack Query stores all pages under one infinite-query key.
Key points
- Include stable filters and page size.
- Exclude
pageParam. - Use serializable key values.
- When a filter changes, the key changes and TanStack Query creates a separate infinite-query entry.
1messages.list.toInfiniteQuery({2 initialPageParam: null as string | null,3 keyVariables: {4 conversationId,5 unreadOnly,6 limit: 20,7 },8 getVariables: ({ pageParam, keyVariables }) => ({9 cursor: pageParam,10 ...keyVariables,11 }),12});Key shape and invalidation
Infinite queries include an "infinite" marker because normal queries and infinite queries store different data shapes and must not share a key.
The final key item is null when keyVariables is omitted, keeping infinite keys a different length from every normal endpoint key.
baseKey() remains a prefix of both key shapes, so one invalidation can refresh every normal and infinite query for the endpoint.
1// Normal query2["main", "posts", "list", { page: 1 }]3 4// Infinite query5["main", "posts", "list", "infinite", { tag: "typescript", limit: 20 }]6 7// Infinite query without key variables8["main", "posts", "list", "infinite", null]9 10queryClient.invalidateQueries({11 queryKey: posts.list.baseKey(),12});What micro-rq and TanStack Query control
micro-rq builds the infinite key, maps pageParam to endpoint variables, performs the request, parses the response, and forwards the cancellation signal to fetch.
TanStack Query stores the pages, calls getNextPageParam, decides when to fetch, exposes fetchNextPage, and controls cache lifetime and refetching.
getNextPageParam stays outside toInfiniteQuery() because it reads your API's response shape.
Key points
- Add
enabled,select, retry, and other TanStack Query options at the hook call. - A cancelled infinite query aborts its current HTTP request.
- Use
hasNextPageandisFetchingNextPagefrom TanStack Query for load-more UI.
