server actions & trpc
Heya folks, I'm compiling some information about pros and cons of these two, in hopes of opening a GH discussion thread that could lead to a PR. I've read through all mentions of this topic on GH and Discord and Reddit, and there doesn't seem to have been a serious discussion about if trpc is still needed. Most comments are either 9 months old and argue unstability, or based on unfounded claims like "trpc is better typesafety" or "better devex" which have no connection to the real world.
Most of them talk about trpc without realizing that trpc is just a transport, and all of the chrome we've built on top of it could remain the same with server actions or even fetch - which means, we should look at the differences between trpc and server actions, transport to transport, and ignore the patterns around them, used by create-t3-app. Is there anything we can do with trpc, that we can't do with server actions?
In the latest Theo video you can hear the actual react press release pit the two against eachother and refer to SAs as a trpc replacement candidate.So, I'd love to hear your experiences. I know for sure that there has been a couple of y'all who tried migrating away from trpc, and hearing your experience would make for an informed decision. I'm also interested in more practical aspects like the cost involved with one of the other, logging and debugging experience, authentication capabilities etc. These are the things that are seldom discussed, but bear huge value in making the decision.
1 Reply
To give more context to the above, I've compiled a list of commonly stated reasons for one or the other, and why those reasons are invalid in this discussion:
☑️ You must have a Data Access Layer - yes, but you can have it with either trpc or server actions, it doesn't really change much.
☑️ trpc gives you better dx - Not significantly better. You get some very nice things, like formatting errors, but on the other hand, the procedure declaration is uglier and more confusing. You win some, lose some.
☑️ trpc gives you better type safety - I'm not entirely sure what that even means. Zod ensures type safety, and linter helps. Both of these work exactly the same with server components.
☑️ you get react query integration in trpc - tanstack query works exactly the same with server components.
☑️ server actions are unstabile - they've been stabile for a while now.
☑️ it's no extra work for you because Create T3 App takes care of all of the initial setup - sure, but the whole point of this conversation is to resolve this point.
❓ trpc has zod built-in - deciding what you use for runtime validation and sanitization is up to you and your controllers, not to trpc, t3 just made a decision to enforce it afaik, and we could do the same with server actions.
So, no real difference between the two in any of those points. Lets focus on more tangible differences surrounding the deployment model and security.
Also wanted to give an example of using react query with server actions, before anyone says it is not possible:
Here is one - its quite hard to organize server actions. You can't really group them into router namespaces like you do with our trpc - instead, each function has to be a function, and you then resort to naming patterns like
Products_getById()
to avoid conflicts