# Add Mutation

> Add a TanStack Query mutation hook for a feature write path with correct cache invalidation and optional optimistic update, keeping server state owned by Query and out of Zustand.

- Skill: `thibautbaissac/add-mutation` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add thibautbaissac/add-mutation`
- Raw SKILL.md: https://api.skillmd.com/api/skills/thibautbaissac/add-mutation/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: thibautbaissac (https://skillmd.com/u/thibautbaissac)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/thibautbaissac/add-mutation

---


# Add a mutation hook

Wire `$target` as a TanStack Query mutation in its feature slice. The cache is
the single source of truth for server data — the mutation invalidates or updates
it, never copies it into Zustand.

## Step 1 — Locate the feature and its query keys

Find the owning feature, its request/response schema (from `/add-api-contract`),
the existing query-key factory, and the project API client (`shared/lib/api`).
Reuse the key factory; do not invent parallel keys.

## Step 2 — Define the mutation

Apply `references/mutation-patterns.md`.
- Type `mutationFn` input from the request schema (`z.infer`); parse the response
  before returning it.
- Call the API client; do not `fetch` inline.

## Step 3 — Keep the cache correct

Choose one:
- **Invalidate** (default): `onSuccess` → `queryClient.invalidateQueries` on the
  affected keys. Simple and correct.
- **Optimistic** (only when UX needs instant feedback): `onMutate` snapshots and
  writes the cache, `onError` rolls back to the snapshot, `onSettled`
  invalidates. Do not optimistically update without a rollback path.

## Step 4 — Surface state, don't duplicate it

Return `isPending`/`error` for callers to drive disabled states and messages.
Never mirror the mutated entity into a Zustand store — read it back from the
query cache.

## Step 5 — Verify

```bash
source "${CLAUDE_PROJECT_DIR}/.claude/lib/detect-toolchain.sh"
run_typecheck
run_tests <feature-hook-test>
```

Test with a fresh `QueryClient` and `retry: false`; assert the cache is
invalidated/updated and that an error rolls back any optimistic write.

## Checklist

- [ ] `mutationFn` input typed from the request schema; response parsed.
- [ ] Submission goes through the API client, not inline `fetch`.
- [ ] Affected query keys are invalidated, or optimistically updated with rollback.
- [ ] No server data mirrored into Zustand.
- [ ] Hook test uses a fresh `QueryClient` with `retry: false`; `run_typecheck` passes.

