T3 Stack Overview
Theo's stack. The three pillars: types, auth, data.
Theo Browne (the "T") and a handful of collaborators looked at how full-stack TypeScript apps actually get built and carved out a short, opinionated list of tools that play well together. The T3 Stack is that list. It's not a framework. It's not a CMS. It's a curated bundle of well-known libraries plus a CLI that wires them up correctly the first time, so you stop debating import order and start writing features.
The bundle
Every T3 app starts with these six choices:
- Next.js for the framework. App Router by default in current versions.
- TypeScript, strict, with no escape hatches in the generated config.
- Tailwind CSS for styling. No component library, just utility classes.
- tRPC for the API. End-to-end types between server and client.
- Prisma or Drizzle for the ORM. Drizzle is the newer recommendation but Prisma remains fully supported.
- Auth.js (the renamed NextAuth.js) for authentication, or you can opt for Better Auth in newer T3 setups.
Plus Zod, which gets used everywhere there's an input or environment variable to validate.
create-t3-app is the canonical entry point.The three pillars
Every decision in the stack maps to one of three goals: types, auth, and data.
Pillar 1: types end to end
TypeScript strict mode is non-negotiable. Zod validates anything crossing a runtime boundary (input from forms, env vars, API bodies). tRPC carries those types across the network without codegen. Prisma/Drizzle generates DB types from your schema. The result: when you rename a column in the database, the failing builds tell you exactly which page to edit.
Pillar 2: auth that works in five minutes
Auth is the place greenfield projects bog down. T3 gives you a pre-wired Auth.js setup with a session callback that exposes the user ID, a Prisma/Drizzle adapter, and a typed auth() helper for Server Components and Server Actions. Add a provider (GitHub, Google, Discord) by uncommenting a block. You can swap to Better Auth for more modern primitives, but the shape is similar.
Pillar 3: data without the API design tax
Prisma or Drizzle define your schema in one file. tRPC procedures wrap that for client consumption. There's no REST route to design, no GraphQL schema to draft, no DTO layer. The same ctx.db you use in a script works in a server component, works in a tRPC procedure, works in a Server Action. One database client, many entry points.
What T3 explicitly does NOT include
Theo is loud about what the stack leaves out, and the omissions are intentional.
- No state management library. No Redux, no Zustand, no Jotai. React state plus React Query (via tRPC) is enough for the apps T3 is aimed at.
- No UI component library.No MUI, no Chakra, no Mantine. Tailwind plus headless primitives (Radix, shadcn) when you need them, but those are your call, not the stack's.
- No CSS-in-JS. Tailwind handles styling. Runtime CSS-in-JS is incompatible with React Server Components and adds size.
- No testing library preference.The stack doesn't pick Vitest vs Jest vs Playwright. You pick.
- No monorepo.Single Next app by default. If you want Turborepo, that's a separate decision (and something Vercel encourages via next-forge for larger teams).
The directory shape you'll see
my-t3-app/
āāā prisma/
ā āāā schema.prisma # or drizzle/schema.ts
āāā src/
ā āāā app/ # Next.js App Router
ā ā āāā layout.tsx
ā ā āāā page.tsx
ā ā āāā api/
ā ā āāā auth/[...nextauth]/route.ts
ā ā āāā trpc/[trpc]/route.ts
ā āāā server/
ā ā āāā api/
ā ā ā āāā root.ts # appRouter
ā ā ā āāā trpc.ts # publicProcedure / protectedProcedure
ā ā ā āāā routers/ # your procedures
ā ā āāā auth.ts # Auth.js config + helper
ā ā āāā db.ts # Prisma/Drizzle client
ā āāā trpc/
ā ā āāā react.tsx # client provider + hooks
ā ā āāā server.ts # server caller for RSCs
ā āāā env.js # Zod-validated env vars
āāā .env.example
āāā package.jsonTwo things to notice. First, every file has a single job, and the names are dull (in a good way). Second, the API/data layer lives under src/server/, mirrored on the client by src/trpc/. That symmetry shows up in every T3 app you'll ever read.
Why use T3 instead of rolling your own
- You stop debating which auth library, which ORM, which fetcher. The choices are made; you can rewire later if you must.
- env.js alone is worth the install. Missing environment variables fail at startup with a clear message, not silently at request time.
- The generated project follows current best practices for the App Router. Outdated tutorials and Pages Router patterns are gone.
- The community is sizeable: every feature you want to add (Stripe, file uploads, image storage) has a discussed solution.
Quiz
Which of these is NOT included by default in a T3 app?
Recap
- T3 = Next.js + TypeScript + Tailwind + tRPC + Prisma/Drizzle + Auth.js (or Better Auth) + Zod.
- Three pillars: types end-to-end, auth wired up, data via ORM + tRPC.
- What it doesn't include is also part of the design: no state lib, no UI lib, no CSS-in-JS, no test runner pick, no monorepo.
env.jsvalidates environment variables at startup. Forget one and the app refuses to boot.- Generate one with
pnpm create t3-app@latest(the next lesson walks through it).