Mutations
Execute mutations with TanStack Query.
import { useMutation } from '@tanstack/react-query';
import { useCRPC } from '@/lib/convex/crpc';
function CreateUser() {
const crpc = useCRPC();
const createUser = useMutation(crpc.user.create.mutationOptions());
return (
<button
disabled={createUser.isPending}
onClick={() => createUser.mutate({ name: 'John', email: 'john@example.com' })}
>
{createUser.isPending ? 'Creating...' : 'Create User'}
</button>
);
}mutationOptions
The mutationOptions method creates options for TanStack Query's useMutation hook.
const crpc = useCRPC();
// Basic usage
const createUser = useMutation(crpc.user.create.mutationOptions());
// With callbacks
const updateUser = useMutation(
crpc.user.update.mutationOptions({
onSuccess: (data) => {
toast.success('Updated successfully');
},
onError: (error) => {
toast.error(error.data?.message ?? 'Update failed');
},
})
);See API Reference for the full signature and options.
Mutation Keys
Get type-safe mutation keys for cache operations:
const crpc = useCRPC();
// Get mutation key
const mutationKey = crpc.user.create.mutationKey();
// => ['convexMutation', 'user:create']Common Patterns
Toast Promise
Use toast.promise for loading/success/error states:
const createProject = useMutation(crpc.project.create.mutationOptions());
const onSubmit = (data: FormData) => {
toast.promise(createProject.mutateAsync({ title: data.title }), {
loading: 'Creating project...',
success: 'Project created!',
error: (e) => e.data?.message ?? 'Failed to create project',
});
};Form Submission
Handle form submission with cleanup:
const updateUser = useMutation(
crpc.user.update.mutationOptions({
onSuccess: () => {
form.reset();
closeModal();
toast.success('Profile updated');
},
onError: () => {
toast.error('Update failed');
},
})
);
const onSubmit = (data: FormData) => {
updateUser.mutate(data);
};Inline Callbacks
Pass callbacks directly to mutate:
const deleteSession = useMutation(crpc.session.delete.mutationOptions());
deleteSession.mutate(
{ id: sessionId },
{
onSuccess: () => router.push('/sessions'),
onError: () => toast.error('Delete failed'),
}
);Actions as Mutations
Convex actions can be used as mutations for external API calls:
// Actions work with mutationOptions
const scrapeLink = useMutation(crpc.scraper.scrapeLink.mutationOptions());
useEffect(() => {
if (url) {
scrapeLink.mutate({ url });
}
}, [url]);
// Access mutation state
if (scrapeLink.isPending) return <Spinner />;
if (scrapeLink.data) return <LinkPreview data={scrapeLink.data} />;Note: Actions don't have real-time subscriptions. Use mutationOptions for one-shot calls to external APIs, or queryOptions if you need query caching.
Next Steps
API Reference
mutationOptions
crpc.path.to.mutation.mutationOptions(
options? // TanStack Query mutation options (except mutationFn)
)All standard TanStack Query mutation options are supported except mutationFn (reserved):
| Option | Type | Description |
|---|---|---|
onSuccess | (data, variables, context) => void | Called on successful mutation |
onError | (error, variables, context) => void | Called on error |
onMutate | (variables) => context | Called before mutation (for optimistic updates) |
onSettled | (data, error, variables, context) => void | Called on completion |
retry | number | boolean | Retry failed mutations |