Can tRPC mutations be safely retried without duplicating writes?
0 reputation · 08 Jul 2025, 02:23 UTC
tRPC does not ship a retry layer; retry behavior is inherited from the query-client integration, which delegates to TanStack Query's mutation options. Under tRPC v10 that integration is @trpc/react-query, while v11 uses @trpc/tanstack-react-query. TanStack Query does not retry mutations by default, unlike queries, because re-issuing a write-shaped request can duplicate the side effect.
The uncertainty arises when a mutation is applied server-side but the response is lost to a network drop or timeout. The client only sees a TRPCError or network error; tRPC's error codes do not encode whether the write committed. Although errorFormatter and TRPCError let you attach custom data, the framework defines no standard idempotency-key mechanism for mutations.
This leaves an application-level design decision: either make the procedure idempotent server-side, for example via a dedupe key, or accept at-most-once semantics and never retry failed mutations. Configuring retries at the transport layer through custom links or batching re-issues the request and reintroduces duplicate-write risk for any procedure that is not idempotent by design.
Does tRPC provide any way to distinguish a mutation that committed from one that failed before application? What is the recommended pattern for making a tRPC mutation idempotent when the client cannot know whether the request reached the server? Which version-specific defaults in the react-query integration and TanStack Query should be confirmed before enabling mutation retries?