My Frontend Stack In 2026
The tools I actually reach for when building production apps, from framework to the moment a user hits a bug.
Share this post & I’ll send you some rewards for the referrals.
Every year, I think my stack is going to change dramatically.
And every year, it changes just a little.
The pieces I keep around are the ones that earn their spot. They don’t fight me, they compose well with each other, and they save me time when something goes wrong.
This isn’t a “best of” list.
It’s nine categories, about fifteen tools, that I keep coming back to in 2026, and why.
A good stack isn’t the newest stack, it’s the one that gets out of your way.
1. Foundations: Next.js, Vite, TypeScript, pnpm
I’ve stopped looking for the “one framework to rule them all”.
I split by use case:
Marketing sites, blogs, docs, anything content-heavy → Next.js. SSR, image optimization, file-based routing, and the App Router make content sites trivial. Deploy to Vercel, and you’re done.
Internal tools, custom portals, dashboards, anything behind auth → Vite 8 + React + TypeScript. No framework opinions, no server I don’t need, instant HMR, and a build that finishes before I can blink.
Vite 8 ships with Rolldown as the bundler (Rust-based, replacing Rollup), and the difference on a real-world SPA is noticeable — production builds that used to take 30+ seconds now finish in under 10.
If you’ve been on an older Vite version, the upgrade is worth it just for this.
Both setups with TypeScript in strict mode from day one. I don’t care if it’s a weekend project — strict: true saves more time than it costs, every time.
pnpm for everything I install. Three reasons:
Install is 2-3x faster than npm on a cold cache, and dramatically faster than that on a warm one — content-addressable storage means a package gets downloaded once on your machine, ever.
Disk usage drops by an order of magnitude if you maintain multiple projects. My laptop went from 40GB of duplicated
node_modulesto under 5GB.Workspaces are first-class. If you split into a monorepo later, you don’t switch tools.
Bun is the serious challenger now and I keep an eye on it, but pnpm is what I trust on production projects.
If you’re starting a new SPA today and reaching for Next.js out of habit, ask yourself if you actually need a server.
Vite is faster to set up, faster to build, and gets out of your way.
2. Tailwind CSS + shadcn/ui
I used to write a lot of CSS. Now I write almost none.
Tailwind handles styling. shadcn/ui gives me accessible component primitives (button, dialog, dropdown, command palette, etc.) that I copy into my repo and own outright. No npm dependency, no version pinning, no surprise breaking changes.
The combination is the closest I’ve come to a “design system without building a design system”.
When I need to customize something, I just open the file and edit it. When the library updates, I read the changelog and decide what (if anything) to pull in.
3. Storybook
If you’re building anything with a real component library, like an internal design system, an app past 20 reusable components, or a team shipping UI fast, Storybook earns its spot.
It pairs especially well with shadcn/ui. Since you own those components, the stories double as documentation: “here’s the Button with all 12 variant + size combinations, plus disabled, loading, and error states”.
When a designer asks, “does this handle long labels?”, you don’t dig through code, you point them at the story.
Caveat: Storybook is overkill for small apps with a handful of bespoke components. The maintenance cost is real. Every component needs its stories kept in sync.
Reach for it when the component count starts to outpace what you can hold in your head.
4. TanStack Query + TanStack Router
TanStack Query was the single biggest improvement to my React code in the last few years.
Server state is not the same as client state, and trying to manage it with useState + useEffect is how you end up with stale data, race conditions, and three different loading spinners that don’t agree with each other.
TanStack Query gives you caching, background refetching, optimistic updates, and pagination through a single library and a coherent mental model. useQuery for reads, useMutation for writes, useInfiniteQuery for paginated lists. After using it, going back to manual fetch logic feels like writing assembly.
TanStack Router is the routing companion I default to in the SPAs (where Next.js’s App Router isn’t doing the work). The reason: it’s the only React router I know of where the params, search params, and loader return types are fully typed end-to-end. You define a route once, and useParams() it infers the right shape. No more params.id as string casting because TypeScript can’t see what’s in the URL.
Note: If you’re already deep in React Router and it’s working, fine, stay. But for a fresh SPA in 2026, TanStack Router is the easy pick.
5. Zustand
For client state, the stuff that doesn’t belong on a server but doesn’t fit cleanly in component state either, I started using Zustand.
A store is a function. Reading it is a hook. There’s no provider, no boilerplate, no actions/reducers/middleware ceremony unless you opt in.
I reach for Zustand when state is shared across multiple components or routes (cart, auth user, sidebar open/closed, undo stack).
For a state that lives in one component, plain useState is still the right answer.
Don't reach for a global store on day one.
6. Zod
I validate everything that crosses a trust boundary.
Every API response, every form input, every environment variable, every value coming back from localStorage.
TypeScript types disappear at runtime. Zod doesn't.
The combo of "compile-time types + runtime validation, both inferred from the same schema" is the closest thing to free reliability I know of.
7. Oxlint + Oxfmt
ESLint has been around for years, but it has become a bit slow on larger codebases.
Then I tried Oxlint and it changed the game.
Oxlint is a Rust-based linter that runs 50-100x faster than ESLint on real codebases. On a project where ESLint takes 15 seconds, Oxlint finishes in well under a second.
That sounds like a small thing until you realize it changes when you run the linter, not just in CI, but on every save, in your editor, without any latency.
For formatting, I pair Oxlint with the Oxfmt. It’s the same Rust toolchain, same parser, same speed story.
The win over a separate formatter is consistency: lint and format come from the same project, so they share their understanding of the syntax tree and you maintain one mental model instead of two.
The speed isn’t a vanity metric. Fast tools change behavior. When linting and formatting are both free, you lint more, format more, and stop arguing about either.
Note: dprint and prettier are also great picks, depending on the size of the codebase and file formats.
8. Vitest + Playwright + MSW
Two tests, two scopes, plus one piece of glue:
Vitest for unit and component tests. It’s Jest-compatible, and runs on Vite’s transform pipeline (so it’s fast and respects your config). It has built-in support for TypeScript, JSX, and ESM with no config gymnastics.
Playwright for end-to-end. E2E testing used to be a nightmare: flaky, slow, hard to debug, hard to write. Playwright fixed all four. There is also a trace viewer that shows you exactly what happened on a failed run, click by click.
MSW (Mock Service Worker) sits underneath both. It intercepts at the fetch / service worker layer, which means a single handler — http.get('/api/users', () => HttpResponse.json([...])). It works in Vitest, in Playwright, in Storybook stories, and against your local dev server.
MSW is the cleanest answer I’ve found to “How do I test code that calls TanStack Query without spinning up a real backend?”.
My split:
Vitest runs on every save and on every commit. Sub-second feedback.
Playwright runs a small smoke suite on every PR (login, checkout, the 2-3 flows that absolutely cannot break) and a fuller suite nightly.
MSW handlers live next to the schemas in
src/mocks/, same fixtures that power tests, dev, and Storybook.
9. Sentry (Error Monitoring + Session Replay)
Once an app is in production, the question stops being “did I write good code?” and becomes “what’s breaking for real users right now?”.
Your unit tests, your E2E tests, and your dev environment can’t answer that.
Error Monitoring is the table-stakes part: stack traces, breadcrumbs, release info, browser and user context, all hooked in automatically by the React and Next.js SDKs.
The feature that changed how I work, though, is Session Replay. This is a DOM-reconstructed playback of the session that produced the error, with the user’s clicks, scrolls, console output, and network requests on a single scrubbable timeline.
The first time I used it, I closed a bug in 5 minutes that I’d been staring at for two hours. The error message said one thing; the replay showed me the user had clicked a button I didn’t even know existed in that state. That’s the loop.
Because Replays are linked to errors, traces, and logs, you can easily jump between them seamlessly.
It also now includes AI-powered replay summaries that automatically analyze a session and provide a play-by-play so you can skip straight to the relevant moment
PS: Use the tshapeddev promo code to get 3 months free on the Team plan of Sentry for any new accounts.
(Thanks to Sentry for partnering on this section.)
Note: The opinions are mine. I've used the product for years.
📌 TL;DR
The full stack:
Next.js for content sites, Vite 8 + Rolldown + TypeScript for SPAs, pnpm to install everything
Tailwind CSS + shadcn/ui for styling and components
Storybook for component dev, docs, and visual regression
TanStack Query + TanStack Router for server state and typed routing
Zustand for client state that needs to be shared
Zod for runtime validation at every trust boundary
Oxlint + Oxfmt for Rust-speed linting and formatting
Vitest + Playwright + MSW for unit, E2E testing, and network mocking
Sentry (Errors + Session Replay) for the moment, something breaks in prod
The pattern, if there is one: each tool does one thing well and composes cleanly with the others. None of them tries to be a platform. None of them lock me in.
The best stack is the one you stop noticing, until it saves you.
What’s in your stack? Reply and let me know what you’d swap.
Follow me on LinkedIn | Twitter(X) | Threads
Thank you for supporting this newsletter.
Consider sharing this post with your friends and get rewards.
You are the best! 🙏





