Every year the React ecosystem resets. What was best practice in January is legacy by December. I’ve stopped trying to keep up with everything — instead I’ve settled on a core stack that I reach for on every client project, and I update it slowly.
Here’s what that stack looks like in 2026.
Next.js + App Router
This isn’t controversial anymore. The Pages Router is effectively in maintenance mode, and the App Router has matured to the point where the sharp edges are mostly filed down. Server Components are the default, "use client" is the exception, and that inversion of logic is finally comfortable.
The trade-off I still see people miss: App Router is worse for highly-interactive, dashboard-style apps where almost everything needs client-side state. If your project is 80% forms and data tables, consider Remix or even plain Vite + React Router. But for content-rich sites, marketing pages, and e-commerce? App Router wins by a mile.
Styling: Tailwind v4 + CSS layers
I was late to Tailwind — held out for years writing vanilla CSS modules. I regret the stubbornness. Tailwind v4 with the CSS @layer integration solves the two things that bothered me: bundle size (zero-runtime) and component composition.
I still write vanilla CSS for animations, keyframes, and any design token that crosses component boundaries. But for 90% of styling, Tailwind is faster and more consistent.
Data: tRPC + Drizzle + SQLite
This is the combination I’ve landed on after trying REST, GraphQL, and every ORM in the Node ecosystem.
- tRPC for type-safe API calls. No schema generation step, no codegen, no double-declaring types. It just works.
- Drizzle for the database layer. It’s thin enough that I still write raw SQL when I want to, but structured enough that migrations are automated and type-safe.
- SQLite (via Turso or libsql) for the database itself. Most client projects don’t need PostgreSQL. SQLite handles thousands of concurrent reads, it’s trivial to back up, and Turso makes it edge-deployable.
If you're reaching for PostgreSQL before you have 10,000 users, ask yourself why.
State: URL-first, then React context, then nothing else
This is my strongest opinion: 90% of application state should live in the URL. Search filters, pagination, selected tab, even draft states — put them in query parameters. It makes the app shareable, bookmarkable, and refreshes without data loss.
For the remaining 10%, React context handles it fine. I’ve never needed Zustand, Jotai, or Redux on a client project. If your state is complex enough to need those, you’re probably building a product — not a website.
The URL is the best state manager. It's been there since 1990 and it doesn't need a bundle.
Testing: Vitest + Playwright
Vitest because it’s fast and speaks the same config as Vite. Playwright because it’s the only E2E tool that doesn’t make me want to quit testing altogether.
I write unit tests for utility functions and API routes. I write E2E tests for the three critical user flows (sign up, purchase, content creation). Everything else gets a visual regression check and a prayer.
Deployment: Vercel or Coolify
For client projects, Vercel is still the easiest path. Zero-config deploys, preview URLs for every branch, and the edge network is genuinely fast. The cost is vendor lock-in, but most clients don’t care about that.
For internal tools or projects where the client wants full control, Coolify on a $10 VPS is surprisingly capable. It’s like an open-source Vercel you host yourself — Docker-based, supports auto-deploys from GitHub, and includes a Postgres database.
The stack at a glance
| Layer | Choice |
|---|---|
| Framework | Next.js 15+ (App Router) |
| Styling | Tailwind v4 + CSS layers |
| Database | SQLite via Turso/libsql |
| ORM | Drizzle |
| API | tRPC |
| Auth | Lucia v3 or NextAuth v5 |
| Testing | Vitest + Playwright |
| Hosting | Vercel or Coolify |
None of this will be current in 2027. But that’s the nature of the ecosystem — you pick the tools that solve today’s problems and stay ready to swap them when the next cycle starts.
— Stephen.