Mutations
TanStack Query primitives for every Better Auth write endpoint.
Every mutation exposes a hook and an options factory. The factory's .mutationKey is the canonical key.
import { useSignInEmail, signInEmailOptions } from "@better-auth-ui/react"Use the hook in components. Use the factory anywhere TanStack Query takes a mutationOptions object — useMutation, useIsMutating, or a global MutationCache observer.
Error handling
Every mutation wires throw: true into fetchOptions, so the promise rejects with a BetterFetchError on failure instead of resolving with { error }. This means you can rely on error, isError, throwOnError, and standard onError handlers from useMutation.
const { authClient } = useAuth()
const { mutate, error } = useSignInEmail(authClient, {
onError: (err) => toast.error(err.message)
})Cache side effects
Hooks that change auth state update the cache for you. Override onSuccess in the hook options and it runs after the built-in side effect:
useSignInEmail/useSignInUsername/useSignInPasskey/useSignUpEmail— reset the session query so the new session is refetched. (useSignInSocialanduseSignInMagicLinkredirect instead, so they leave the cache alone.)useSignOut— remove every["auth", ...]query.useUpdateUser— optimistically merge the update into the cached session, then refetch.useSetActiveSession— optimistically swap the cached session, scroll to top, and refetch both the session and device-session queries.useChangeEmail— refetch the session.useAddPasskey/useDeletePasskey— refetch the passkey list.useRevokeSession— refetch the sessions list.useRevokeMultiSession— refetch the device sessions list.useUnlinkAccount— refetch the linked accounts list.
Tracking mutation state globally
All mutation keys are prefixed with "auth" and exposed through the shared authMutationKeys factory in @better-auth-ui/core. Use it instead of inlining tuples so call sites share the same source of truth as the mutation factories:
import { authMutationKeys } from "@better-auth-ui/core"
import { useIsMutating } from "@tanstack/react-query"
const authPending = useIsMutating({ mutationKey: authMutationKeys.all })
const signInPending = useIsMutating({ mutationKey: authMutationKeys.signIn.all })
const emailSignInPending = useIsMutating({
mutationKey: authMutationKeys.signIn.email
})Each grouping (signIn, signUp, passkey, multiSession) exposes an all prefix so you can match a whole feature at once.
Match inside a MutationCache observer for global toasts or analytics:
import { authMutationKeys } from "@better-auth-ui/core"
new MutationCache({
onError: (error, _vars, _ctx, mutation) => {
if (mutation.options.mutationKey?.[0] === authMutationKeys.all[0]) {
toast.error(error.message)
}
}
})Escape hatch
For write-style endpoints without a purpose-built hook, use useAuthMutation (or its options factory authMutationOptions). Read-style endpoints should use useAuthQuery instead.
import { useAuth, useAuthMutation } from "@better-auth-ui/react"
const { authClient } = useAuth()
const { mutate } = useAuthMutation(
authClient.emailOtp.sendVerificationOtp,
["auth", "emailOtp", "sendVerificationOtp"]
)
mutate({ email: "[email protected]", type: "sign-in" })Variables are inferred from authFn's parameter — required params reject mutate() at the type level, optional-param methods (e.g. signOut) allow it. throw: true is wired into fetchOptions so onError and error get a BetterFetchError.
For shared mutation registration (useIsMutating, a global MutationCache observer, manual useMutation), use the factory directly:
authMutationOptions(authClient.emailOtp.sendVerificationOtp, [
"auth",
"emailOtp",
"sendVerificationOtp"
])For endpoints that already have a key in authMutationKeys, prefer it over an inline tuple so cache observers and useIsMutating checks line up.
Available mutations
Auth
useSignInEmail
useSignInUsername
useSignInMagicLink
useSignInPasskey
useSignInSocial
useSignUpEmail
useSignOut
useRequestPasswordReset
useResetPassword
useSendVerificationEmail
useIsUsernameAvailable
Settings
useUpdateUser
useChangeEmail
useChangePassword
useDeleteUser
useLinkSocial
useUnlinkAccount
useAddPasskey
useDeletePasskey
useRevokeSession
useRevokeMultiSession
useSetActiveSession
useCreateApiKey
useDeleteApiKey
Organization
Last updated on