DEV Community

Cover image for Why I chose T3 stack as the full-stack to build the react app
JS for ZenStack

Posted on • Edited on

Why I chose T3 stack as the full-stack to build the react app

What is T3 stack?

The "T3 Stack" is a web development stack made by Theo focused on simplicitymodularity, and full-stack typesafety. It consists of:

create-t3-app is the simple CLI made by @nexxeln to scaffold a starter project using the t3 stack. If you haven’t tried the stack yet, seeing the rocket rising curve of the star, which climb to more than 11k within six months, how not to try it as a modern developer 😉

T3 star

Why it is perfect for me

Believe it or not, I actually chose T3 stack before I was aware of it. I was very happy to finally choose the ‘perfect’ full stack as the standard for the web apps I’m going to build after lots of research on the market. Then all of sudden T3 rushed into my eyes, with everything perfectly matched, the feeling was kind of mixed like below:

Mixed feeling

I think the reason why I end up choosing the same stack as the T3 stack is that I totally agree with the Axioms of T3.

  1. Solve Problems

    It's easy to fall into the trap of "adding everything" - we explicitly don't want to do that. Everything added to create-t3-app should solve a specific problem that exists within the core technologies included.

  2. Bleed Responsibly

    We love our bleeding edge tech. The amount of speed and, honestly, fun that comes out of new shit is really cool. We think it's important to bleed responsibly, using riskier tech in the less risky parts.

  3. Typesafety Isn't Optional

    The stated goal of create-t3-app is to provide the quickest way to start a new full-stack, typesafe web application. We take typesafety seriously in these parts as it improves our productivity and helps us ship fewer bugs.

Both 2 and 3 are important principles for me when choosing the stack.

What about alternatives?

“Every coin has two sides,” so why choose this over other alternatives? Well, generally speaking, I think it depends on what you have and what you believe. I will show you mine one by one.

  1. TypeScript

    Despite “Typesafety Isn't Optional” being the principle, I don’t think we need to discuss TypeScript vs. JavaScript anymore. It’s 2022 already.

  2. Tailwind CSS

    As a long-time backend developer who recently came to the frontend world, CSS was always the most difficult monster for me. After reading “a few thousand words” from Tailwind CSS’s creator Adam Wathan, my long-time fuzzy feeling about the CSS trouble is finally clear — the best way of managing CSS is not to write CSS at all.

    Therefore, I totally got to buy in for the utility-first approach. In that world, the only thing is worth mentioning is Tachyons. However, although it came way earlier than Tailwind, it is said to be feature-complete, and one cannot expect new features to be added or problems discussed. The latest release is almost five years old, which definitely violates the principle “Bleed Responsibly”. You can also see that from the star trend:
    TailWind star

  3. Next.js

    Originally I thought this one was another no need to discuss like Typescript as the dramatic fanfare Nextjs and Vercel brought to the frontend world. But during writing this article, I noticed an upstart: Remix.

    To be honest, I don’t have too much information about Remix. But Theo did make a point about the Remix in one of his tweets as below:

    Remix vs Next
    Although the volume is not compared to Next.js now, it brings interesting experience improvements like Rewrite, Mutation, Unhandled Errors, etc. Also, it has a good rising trend. Maybe it would be another bleeding edge, so let’s keep an eye on it.

    Remix

  4. NextAuth.js

    If you want a full-featured authentication system with built-in providers (Google, Facebook, GitHub…), JWT, JWE, email/password, magic links, and more… use [next-auth](https://github.com/nextauthjs/next-auth-example).

    That’s specified in the official document of Next.js.

  5. Prisma

    Since “Typesafety Isn't Optional,” ORM is mandatory.

    Personally, this is the only area that comes with a real competitor: TypeORM

    Prisma vs TypeORM

    Leave alone the star trend, Prisma’s lack of stability, as they made breaking changes for both version 2 and version 3, is a major turnoff for some people.

    Actually, I have been using TypeORM myself for several years, and everything works just fine.

    Then why change to Prisma?

    The major reason is still the principle “Typesafety Isn't Optional.” Because Prisma generates types for its queries on the fly, So there are numerous situations it can provide stronger guarantees for the types of query results than TypeORM.

    Another consideration is that TypeORM is closer to mirroring SQL in its API like the ILike below:

    const posts = await postRepository.find({
      where: {
        title: ILike('Hello World'),
      },
    })
    

    It is not a problem for a backend developer, but as a full-stack solution, it’s better to try to avoid the SQL concept at all.

  6. tRPC

    Looking at the headline of the website of tRPC, you definitely know why I choose it.

    tRPC

    Yes, still, “Typesafety Isn't Optional.”

    If you are using GraphQL, you might think it also gets typesafety in the end because of the agreed schema between the frontend and backend. It is probably best for the separated frontend and backend(which has an unavoided version management issue), but not for the full-stack monorepo. It has to go through the code-generating process which comes with the price of a long time for type checking, less intelligence support of IDE, and a larger client bundle size. Furthermore, it indeed introduce a new non-trivial terminology, which means you need to first learn and understand it well before get it correct.

    tRPC instead relies on one very large assumption: Your server is written in TypeScript, and is co-located with the client code. tRPC has you define a server-side router for your procedures, then export the type of that which Typescript automatically infers, and then import that type to be used on the client side. Since types are automatically removed when Typescript code is compiled, there is no extra code added to the client bundle, and no extra types to slow down the type checker. Just type safety.

    It come from a post for a real case of switching from GraphQL to tRPC which elaborate in detail about the comparison between GraphQL and tRPC.

Confession

There is one thing I need to confess, although I do consider using tRPC at first, I end up not using it.

One reason is that since Prisma already generates CRUD for the backend, why not take one step further to generate the frontend query too?

Another reason is that client is not get to pick which fields it fetches compared to GraphQL.

I end up using the new toolkit ZenStack: A toolkit for building secure CRUD apps with Next.js + Typescript. You will get typesafety hooks for every data type defined in the schema without having to define the API. Moreover, it’s client who decide what the result looks like.

See the actual stack I’m using to build a SaaS app:

Top comments (0)