---
title: Mutations
description: Execute finite writes without implicit retries or an offline queue.
pagination: false
sidebar:
  icon: send
---

Use a mutation for a request that changes application state, and track whether the server accepted it.

> **Before you begin**
>
> Complete [frontend installation and contract pull](/docs/modules/client) before using this guide.
> Keep its selected React/query peers and generated declarations in the frontend package.

## Submit once

`useRouteMutation` never runs on mount and defaults to no retry. Known-offline work fails as
`not-sent`; after a request is handed to `fetch`, timeout or disconnect is conservatively `unknown`.
RELKIT stores only scoped reconciliation metadata in `sessionStorage`, never variables or retry
payloads. Application mutations need an application-owned status endpoint to reconcile an unknown
outcome.

Every managed write carries the rendered identity scope and session epoch as a precondition. The
server authenticates independently and compares them before application code runs.

## Call a defined route

The backend's [Echo `defineRoute`](/docs/modules/http/define#expose-one-public-function) generates
`POST /echo`. Render this component under the provider after pulling that backend's contract:

```tsx title="src/EchoButton.tsx"
"use client";

/** Calls the documented POST /echo function route after an explicit user action. */
import { useRelkitClient, useRouteMutation } from "@relkit/client/react";

/** Sends domain input and renders the validated output; the hook owns mutation state.
 * @returns An Echo button with pending, failure, and success feedback. */
export function EchoButton() {
  const { status } = useRelkitClient();
  const echo = useRouteMutation("POST /echo");

  return (
    <section>
      <button
        disabled={status !== "ready" || echo.isPending}
        onClick={() => echo.mutate({ message: "Hello from the frontend" })}
      >
        Send message
      </button>
      {echo.isPending && <p role="status">Sending…</p>}
      {echo.isError && <p role="alert">{String(echo.error)}</p>}
      {echo.isSuccess && <p>{echo.data.message}</p>}
    </section>
  );
}
```

The hook infers `{ message }` input and `data.message` from the target function. For a real write,
refresh the affected [`useRoute` query](/docs/modules/client/routes) in `onSuccess`. Reconcile an
uncertain result before retrying a non-idempotent operation. See
[`useRouteMutation`](/docs/api/client#useroutemutation) for all options and
[offline writes](/docs/modules/client/offline) for recovery.

{/* Generated by apps/docs/scripts/generate.ts. Do not edit. */}

**Reference and source**

- [`@relkit/client` API](/docs/api/client)
- [`@relkit/routes` API](/docs/api/routes)

- [`apps/docs/examples/frontend/echo.tsx`](https://github.com/rel-kit/relkit/blob/main/apps/docs/examples/frontend/echo.tsx)
