The intelligent data layer for Next.js. Simplify your app with automatic caching, seamless hydration, and built-in cost-saving logic.
📚 For comprehensive guides and a full API reference, visit the next-nexus official docs.
next-nexus enhances native Next.js data fetching with a powerful, automated caching and hydration layer. It provides a minimal, predictable API for both Server and Client Components, enabling you to build fast, cost-effective applications with ease.
next-nexus solves common data management challenges in the Next.js App Router:
- Eliminates UI Flicker & Duplicate Requests: Data fetched on the server is automatically hydrated to the client, preventing duplicate requests and ensuring a smooth user experience.
- Reduces Server Costs & TTFB: Rendering delegation allows the server to skip component rendering if the client already has cached data, improving initial page load speed and reducing operational costs.
- Saves Bandwidth: ETag-based conditional requests prevent re-downloading unchanged data.
- Simplifies Cache Management: Precise, tag-based revalidation allows you to invalidate specific data in both server and client caches with a single action.
- Automatic Hydration: Server-fetched data is seamlessly transferred to the client, eliminating client-side refetching on mount.
- Rendering Delegation: Using <NexusRenderer>, the server can delegate rendering to the client if cached data is available, reducing TTFB and server load.
- ETag-Powered Conditional Requests: Uses HTTP ETag and 304 Not Modified responses to avoid re-downloading data the client already has.
- Unified API definition: createNexusDefinition provides a single source of truth for API calls, ensuring type safety and consistent data fetching on both server and client.
Requires: Next.js >= 14.0.0, React >= 18.2.0
Include NexusRuntime once in your root layout, just before the closing </body> tag. This component initializes the client-side cache and sends client cache metadata to the server during RSC requests to optimize data fetching.
To transfer server-fetched data to the client, you must wrap the data-fetching segment (page or layout) with NexusHydrationBoundary.
The standard method is to create a layout.tsx file and wrap children with the <NexusHydrationBoundary> component. This is useful for segments where multiple pages share the same data-fetching logic. For segments that don't need a layout, use the withNexusHydrationBoundary HOC described below.
For simple segments that don't require a separate layout.tsx file, you can use the withNexusHydrationBoundary HOC (Higher-Order Component) pattern directly in your page.tsx.
- Use createNexusDefinition to create reusable, type-safe definitions for your API endpoints.
- Use interceptors to set up request/response interceptors.
Use nexus to fetch data in Server Components. The data will be automatically hydrated.
Use useNexusQuery in a Client Component. It will instantly render with the hydrated data from the server, with no extra request.
-
nexus (Server): The primary way to fetch data in Server Components. It integrates with Next.js's fetch and automatically collects data for hydration.
-
useNexusQuery (Client): A React hook for querying data in Client Components. It provides pending/error states and automatically uses hydrated data.
-
useNexusInfiniteQuery (Client): A powerful hook for implementing "infinite scroll" and pagination. It starts from an initialPageParam and dynamically fetches the next page via the getNextPageParam function.
// app/products/InfiniteProductList.tsx 'use client'; import { useNexusInfiniteQuery } from 'next-nexus/client'; import { productDefinition } from '@/api/productDefinition'; export const InfiniteProductList = () => { const { data, isPending, hasNextPage, revalidateNext } = useNexusInfiniteQuery(productDefinition.infiniteList, { initialPageParam: null, // Start with no cursor for the first page getNextPageParam: lastPage => { // Assuming the API response includes a cursor for the next page. // e.g., { products: [...], nextCursor: 'some-cursor' } return lastPage.nextCursor ?? null; }, }); const allProducts = data?.pages.flatMap(page => page.products) ?? []; return ( <div> {/* ... render allProducts */} <button onClick={() => revalidateNext()} disabled={!hasNextPage || isPending} > {isPending ? 'Loading...' : 'Load More'} </button> </div> ); };
NexusRenderer is a key component for optimizing server rendering. If valid data already exists in the client cache, the server skips rendering and delegates this task to the client. This significantly reduces TTFB (Time to First Byte) and server costs.
You must pass the server presentational component to serverComponent, and for clientComponent, pass the client version of that component which has been re-exported from a file with a 'use client' directive. This component receives the fetched data via the data prop from NexusRenderer, along with any other props passed through componentProps.
-
useNexusMutation: A hook for performing CUD (Create, Update, Delete) operations in Client Components. Ideal for when you need to affect data and update the UI.
// components/AddProduct.tsx 'use client'; import { revalidateServerTags } from 'next-nexus'; import { useNexusMutation, revalidateClientTags } from 'next-nexus/client'; import { productDefinition } from '@/api/productDefinition'; import { useState } from 'react'; export const AddProduct = () => { const [name, setName] = useState(''); const { mutate, isPending } = useNexusMutation(productDefinition.create, { onSuccess: async () => { // On success, revalidate the 'products' tag to update the list. await revalidateServerTags(['products']); // revalidateServerTags is a Server Action, so it can be used in Client Components. revalidateClientTags(['products']); setName(''); }, }); const handleSubmit = () => { if (!name) return; mutate({ name }); }; return ( <div> <input value={name} onChange={e => setName(e.target.value)} disabled={isPending} /> <button onClick={handleSubmit} disabled={isPending}> {isPending ? 'Adding...' : 'Add Product'} </button> </div> ); }; -
useNexusAction & useNexusFormAction: Convenient wrappers for calling Server Actions from Client Components, complete with pending states and lifecycle callbacks.
'use client'; import { useNexusFormAction } from 'next-nexus/client'; const ProductForm = () => { const { formAction, isPending, isSuccess } = useNexusFormAction( async (formData: FormData) => { 'use server'; // ...server logic return { ok: true }; } ); return ( <form action={formAction}> <input name='name' /> <button type='submit' disabled={isPending}> Save </button> {isSuccess && <div>Saved!</div>} </form> ); };
- Tag-Based Revalidation: Invalidate server and client caches based on tags to ensure data consistency.
- revalidateServerTags: Revalidates the Next.js data cache on the server.
- revalidateClientTags: Revalidates the in-memory cache on the client.
- Direct Cache Access (nexusCache): A utility to directly get, set, or invalidate specific cache entries on the client for advanced use cases like optimistic updates.
- Interceptors: Attach custom logic to the request/response lifecycle. Useful for adding authentication headers, logging, or transforming data.
Import from the correct subpath to ensure you're using the right code for the environment.
- next-nexus (Universal):
- createNexusDefinition: Creates an API definition.
- interceptors: Adds logic to the global request/response lifecycle.
- revalidateServerTags: Invalidates the Next.js data cache based on tags.
- next-nexus/server (Server only):
- nexus: Requests data in Server Components and registers it for hydration.
- NexusRenderer: A component that enables rendering delegation.
- NexusHydrationBoundary: Wraps a Server Component tree to collect hydration data.
- withNexusHydrationBoundary: An HOC version for pages.
- next-nexus/client (Client only):
- useNexusQuery: A hook for querying data in Client Components.
- useNexusInfiniteQuery: A hook for infinite scrolling and pagination.
- useNexusMutation: A hook for CUD (Create, Update, Delete) operations.
- useNexusAction & useNexusFormAction: Wrapper hooks for Server Actions.
- NexusRuntime: Initializes the client runtime and cache.
- nexusCache: A utility for direct access to the client cache.
- revalidateClientTags: Invalidates the client cache based on tags.
- next-nexus/errors (Errors):
- isNexusError: A type guard to check if an error is of type NexusError.
- Request lifecycle logs (START/SUCCESS/ERROR/TIMEOUT) are printed in development by default.
- To enable detailed cache logs (HIT/HIT-STALE/MISS/SKIP/MATCH/SET/UPDATE/DELETE), add the following environment variable.
MIT