Skip to Content
API ReferenceHooksuseNexusQuery

useNexusQuery

useNexusQuery is a client-side hook for fetching, caching, and revalidating data defined by a definition. It’s designed for reading data in Client Components.

Import

import { useNexusQuery } from 'next-nexus/client';

Signature

useNexusQuery<TData, TSelectedData = TData>( definition: NexusDefinition<TData>, options?: { ... } ): { data: TSelectedData | undefined headers: Headers | undefined error: Error | null isPending: boolean isPendingBackground: boolean isSuccess: boolean isError: boolean revalidate: () => Promise<void> }
  • definition: A GET definition object. The hook will throw an error if a non-GET definition is passed.
  • options: An optional object to configure the hook’s behavior. See Options below.

Core Concepts

Hydration-Aware Fetching

useNexusQuery is aware of data fetched on the server and passed to the client via hydration. If data is available in the client cache upon mount, it will be rendered instantly without a new fetch, eliminating UI flickers.

Foreground vs. Background Revalidation

The hook automatically determines the revalidation mode when revalidate() is called or when automatic revalidation events (mount, window focus) occur:

  • Foreground: If no cached entry exists, or if keepStaleData is false and the entry is stale. This sets isPending to true.
  • Background: If a stale entry exists and keepStaleData is true (the default). This sets isPendingBackground to true, while isPending remains false.
  • No-op: If a fresh entry exists, no fetch is performed.

State Flags and UX

  • isPending: true during a foreground fetch. Use this to show a loading state like a spinner, especially when no data is yet available (isPending && !data).
  • isPendingBackground: true during a background fetch. Use this to show a more subtle loading indicator (e.g., disabling a refresh button) while stale data remains visible.

Options

  • route?: string - Proxies the request through a Next.js Route Handler. When provided, the runtime clears baseURL from the definition and uses the route as the effective endpoint.
  • enabled?: boolean (default: true) - If set to false, the hook will not fetch data or subscribe to cache updates.
  • select?: (data: TData) => TSelectedData - A function to select or transform the data. The component will only re-render if the selected value changes.
  • revalidateOnWindowFocus?: boolean (default: true) - Automatically revalidates when the window is refocused.
  • revalidateOnMount?: boolean (default: true) - Automatically revalidates on mount if the data is stale.
  • keepStaleData?: boolean (default: true) - If true, stale data is kept on screen while a background revalidation occurs. If false, data becomes undefined during a foreground revalidation.

Examples

Basic Usage

'use client'; import { useNexusQuery } from 'next-nexus/client'; import { productDefinition } from '@/api/productDefinition'; export function ProductListClient() { const { data, isPending } = useNexusQuery(productDefinition.list); if (isPending && !data) return <div>Loading...</div>; const products = data ?? []; return ( <ul> {products.map(p => ( <li key={p.id}>{p.name}</li> ))} </ul> ); }

Using the select Option

'use client'; import { useNexusQuery } from 'next-nexus/client'; import { statsDefinition } from '@/api/statsDefinition'; export function TotalCount() { const { data: count } = useNexusQuery(statsDefinition.summary, { select: s => s.total, }); return <div>Total: {count ?? 0}</div>; }

Using a route Override

'use client'; import { useNexusQuery } from 'next-nexus/client'; import { productDefinition } from '@/api/productDefinition'; export function ProductListViaRoute() { const { data } = useNexusQuery(productDefinition.list, { route: '/api/products' }); return <div>{data?.length ?? 0} items</div>; }

Reading Cached Headers

'use client'; import { useNexusQuery } from 'next-nexus/client'; import { listWithTotalDefinition } from '@/api/productDefinition'; // Assuming this exists export function ProductListWithTotal() { const { data, headers } = useNexusQuery(listWithTotalDefinition); const total = headers?.get('x-total-count'); return ( <div> Items: {data?.length ?? 0} / Total: {total ?? 'n/a'} </div> ); }

See also

Last updated on