Skip to Content
Core ConceptsWriting Data

Writing Data

Choose the right tool for changing data and keeping your views in sync.

Quick chooser

  • useNexusMutation: For client-initiated API calls where you want full control over the lifecycle.
  • useNexusAction: A wrapper for Server Actions, ideal when a server round-trip is preferable.
  • useNexusFormAction: For ergonomic integration of Server Actions with an HTML <form>.

Revalidation

  • Client cache: Call revalidateClientTags(['tag']) to update data on the client.
  • Server cache (ISR): Call await revalidateServerTags(['tag']) to update server-rendered content.

1. Client-side Mutations

Use useNexusMutation for standard client-side data changes.

"use client"; import { useNexusMutation, revalidateClientTags } from "next-nexus/client"; import { todosDefinition } from "@/definitions"; export function AddTodo() { // Pass a factory: (variables) => NexusDefinition const { mutate, isPending } = useNexusMutation(todosDefinition.create, { onSuccess: () => { // Revalidate lists tagged with "todos" on the client revalidateClientTags(["todos"]); }, }); return ( <button onClick={() => mutate({ title: "New" })} disabled={isPending}> Add </button> ); }

2. Server Actions

Use useNexusAction to wrap a Server Action, which is useful for logic that must run on the server.

"use client"; import { useNexusAction, revalidateClientTags } from "next-nexus/client"; import { revalidateServerTags } from "next-nexus"; // Note: this is a universal import export function AddTodoButton() { const { execute, isPending } = useNexusAction( async (title: string) => { "use server"; // Perform your write operation (e.g., call a DB) // ... await revalidateServerTags(["todos"]); return { ok: true }; }, { onSuccess: () => revalidateClientTags(["todos"]), } ); return ( <button onClick={() => execute("New Title")} disabled={isPending}> Add Todo </button> ); }

3. Form Actions

Use useNexusFormAction to bind a Server Action directly to a form.

"use client"; import { useNexusFormAction, revalidateClientTags } from "next-nexus/client"; import { revalidateServerTags } from "next-nexus"; // Note: this is a universal import export default function Form() { const { formAction, isPending } = useNexusFormAction( async (formData: FormData) => { "use server"; const title = String(formData.get("title") ?? ""); // Perform your write operation // ... await revalidateServerTags(["todos"]); return { ok: true }; }, { onSuccess: () => revalidateClientTags(["todos"]), } ); return ( <form action={formAction}> <input name="title" /> <button type="submit" disabled={isPending}> Add </button> </form> ); }

Tips

  • Prefer tag-based revalidation over manual cache writes (nexusCache). It’s more predictable and ensures data is refetched consistently across all components.
  • Call revalidateClientTags in onSuccess and revalidateServerTags inside your Server Action to keep client and server data in sync.
  • For optimistic UI, use local component state. The subsequent revalidation will ensure consistency with the server state.

See also: useNexusMutation, useNexusAction, useNexusFormAction, Revalidation.

Last updated on