Files
Alejandro Gutiérrez d3163a5bff feat(db): mesh data model — meshes, members, invites, audit log
- pgSchema "mesh" with 4 tables isolating the peer mesh domain
- Enums: visibility, transport, tier, role
- audit_log is metadata-only (E2E encryption enforced at broker/client)
- Cascade on mesh delete, soft-delete via archivedAt/revokedAt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:19:32 +01:00

4.1 KiB

title, description, url
title description url
Mutations Learn how to mutate data on the server. /docs/web/api/mutations

Mutations

As we saw in adding new endpoint, mutations allow us to modify data on the server, like creating, updating, or deleting resources. They can be defined similarly to queries using our API client.

Just like queries, mutations can be executed either server-side or client-side depending on your needs. Let's explore both approaches.

Server actions

Next.js provides server actions as a powerful way to handle mutations directly on the server. They're particularly well-suited for form submissions and other data modifications.

Using our api client with server actions is straightforward - you simply call the API function on the server.

Here's an example of how you can define an action to create a new post:

<Tabs items={["With helper", "Without helper"]}> ```tsx // [!code word:handle] "use server";

import { revalidatePath } from "next/cache";

import { handle } from "@turbostarter/api/utils";

import { api } from "~/lib/api/server";

export async function createPost(post: PostInput) {
  try {
    await handle(api.posts.$post)(post);
  } catch (error) {
    onError(error);
  }

  revalidatePath("/posts");
}
```
```tsx "use server";
import { revalidatePath } from "next/cache";

import { api } from "~/lib/api/server";

export async function createPost(post: PostInput) {
  const response = await api.posts.$post(post);

  if (!response.ok) {
    return { error: "Failed to create post" };
  }

  revalidatePath("/posts");
}
```

In the above example we're also using revalidatePath to revalidate the path /posts to fetch the updated list of posts.

useMutation hook

On the other hand, if you want to perform a mutation on the client-side, you can use the useMutation hook that comes straight from the integration with React Query.

<Tabs items={["With helper", "Without helper"]}> ```tsx // [!code word:handle] import { handle } from "@turbostarter/api/utils";

import { api } from "~/lib/api/react";

export function CreatePost() {
  const queryClient = useQueryClient();
  const { mutate } = useMutation({
    mutationFn: handle(api.posts.$post),
    onSuccess: () => {
      toast.success("Post created successfully!");
      queryClient.invalidateQueries({ queryKey: ["posts"] });
    },
  });

  return <form onSubmit={...} />;
}
```
```tsx import { api } from "~/lib/api/react";
export function CreatePost() {
  const queryClient = useQueryClient();
  const { mutate } = useMutation({
    mutationFn: async (post: PostInput) => {
      const response = await api.posts.$post(post);

      if (!response.ok) {
        throw new Error("Failed to create post!");
      }
    },
    onSuccess: () => {
      toast.success("Post created successfully!");
      queryClient.invalidateQueries({ queryKey: ["posts"] });
    },
  });

  return <form onSubmit={...} />;
}
```