Home / Articles / Choosing a Startup Frontend Stack That Optimizes for Shipping Speed

This article is published in English.

Choosing a Startup Frontend Stack That Optimizes for Shipping Speed

A decision guide for picking an MVP frontend stack: Next.js or Vite, Tailwind with shadcn/ui, TanStack Query plus Zustand, Supabase or tRPC, and what to avoid.

1415 words

Early-stage teams often lose weeks arguing about Next.js versus Remix, Redux versus Zustand, or GraphQL versus tRPC before a single screen exists. Startups rarely fail because of a framework choice; they fail because they ship too slowly. This guide lays out a pragmatic frontend stack for a new product, explains the reasoning behind each layer, and flags the choices that quietly drain velocity, so you can make the decision in an afternoon and move on.

What the stack should optimize for

A startup frontend has three priorities: time to market, developer experience, and type safety. Scale is not on that list yet. You do not need to handle millions of concurrent users on launch day; you need to reach product-market fit before the runway ends. Every tool below is judged against that goal, and anything that exists mainly to look good on a résumé is out.

The core framework: two paths, chosen by product type

For most teams the decision narrows to Next.js with the App Router or a plain React single-page app built with Vite. The deciding question is whether the product needs to be found and rendered quickly by people who are not logged in.

Next.js App Router for public, SEO-sensitive products

SaaS marketing pages, marketplaces, and anything where search visibility, first load time, or full-stack features matter point to Next.js. React Server Components come built in, so data can be fetched on the server and those components ship no JavaScript to the browser. Keeping API routes and UI in one repository also cuts context switching for a small team.

The price is a real learning curve. Everyone on the team has to understand where the boundary between Server and Client Components sits, and misplacing it is a common source of confusing errors.

Vite plus React Router for apps behind a login

Internal dashboards, highly interactive tools in the spirit of Figma or Canva, and B2B products that live behind authentication gain little from server rendering. Vite gives near-instant dev server startup and a pure SPA model that is simpler and lighter, with no SSR hydration mismatches to debug. If SEO is irrelevant, this path usually means fewer moving parts.

Styling and UI: Tailwind CSS with shadcn/ui

Large hand-written stylesheets and heavyweight, hard-to-customize component kits such as Material UI or Bootstrap are a poor fit for a team that iterates daily.

Tailwind CSS for styling

Utility-first styling has become the mainstream default. The generated CSS stays small, class names never collide, and you style directly in JSX. The first days feel slow, but once the utility names become muscle memory, building screens is fast.

shadcn/ui for components

shadcn/ui is not an npm dependency in the usual sense. It is a set of accessible, reusable components built on Radix UI that you copy into your own codebase. Because you own the source, changing a dropdown animation or a button's internal behavior is just an edit, not a fight with a library API, and the defaults already look polished.

The trade-off is that you also own maintenance: upstream fixes do not arrive through a version bump, so pull in updates deliberately when they matter.

State and data fetching: separate server state from client state

Putting API responses into a global Redux store is no longer the default recommendation. The more useful split is between data that lives on a server and state that exists only in the UI.

TanStack Query for server state

Fetching, caching, loading and error states, and background refetching are solved problems. TanStack Query (formerly React Query) handles them and removes most of the boilerplate teams used to write around data fetching. If you want a concrete structure for it, see our guide to structuring a TanStack Query data layer.

Zustand for client state

Global UI state, such as whether the sidebar is open or which theme is active, fits Zustand well. It is tiny (under 1 KB), needs almost no boilerplate, and does not require providers around the app.

The rule is simple: if the data comes from a database, it belongs in TanStack Query; if it only describes the UI, it belongs in Zustand. Mixing the two is where most state bugs in young codebases come from.

The backend shortcut: Supabase or tRPC with Drizzle

Frontend engineers at startups frequently end up owning the backend too, and how the UI talks to the database has a large effect on speed.

Supabase when there is no backend team

Supabase, an open-source alternative to Firebase, provides a Postgres database, auto-generated REST and GraphQL APIs, realtime subscriptions, and authentication. A working backend can come together in an afternoon. Plan early for how you secure data access, because with a BaaS the database rules are your API's security model.

tRPC and Drizzle for a custom backend

On Next.js with a custom backend, tRPC gives end-to-end type-safe APIs without a code generation step. Change a schema on the server and the client immediately shows a TypeScript error. Drizzle ORM adds a lightweight, typed database layer underneath. This setup assumes TypeScript on both sides, ideally in one repository. Teams adopting tRPC incrementally may find our piece on catching API contract drift with a tRPC rollout useful.

Tooling and developer experience

This layer is invisible to users but decides whether the codebase stays maintainable:

  • TypeScript in strict mode. Treat it as non-negotiable. It catches bugs before production and doubles as documentation for new teammates.
  • Biome instead of ESLint plus Prettier. It is written in Rust, lints and formats in milliseconds, needs little configuration, and trims CI time on every run. Check first that it covers any framework-specific lint rules you depend on.
  • Vercel or Cloudflare Pages for deployment. Skip hand-configured EC2 instances or Docker images for the frontend. A git push is enough: Vercel suits Next.js, Cloudflare suits Vite SPAs, and either platform takes care of edge delivery, per-branch previews, and scaling.

The anti-stack: what to leave out

Moving fast depends as much on what you refuse to build:

  • Micro-frontends. They solve the coordination problems of many independent teams. A startup has one team; build a single app or a monorepo.
  • Redux for an MVP. Unless the product is a complex, offline-first collaborative tool, it adds ceremony you will not need.
  • A custom design system. Weeks spent on bespoke button variants are weeks not spent on users. Start with shadcn/ui, adjust the CSS variables to your brand, and revisit later.

Cheat sheet

  • Framework: Next.js App Router for public, SEO-driven products; Vite plus React Router for logged-in apps.
  • Styling: Tailwind CSS.
  • Components: shadcn/ui on Radix UI.
  • Server state: TanStack Query.
  • Client state: Zustand.
  • Backend: Supabase without a backend team; tRPC plus Drizzle for a custom one.
  • Tooling: strict TypeScript and Biome.
  • Hosting: Vercel or Cloudflare Pages.

Wrapping up

The best stack is the one that stays out of your way. Proven tools such as Next.js, Tailwind, shadcn/ui and TanStack Query do not just produce code faster; they buy time to talk to users, iterate on features, and find product-market fit. None of these choices is permanent, either: each layer can be swapped once real usage shows where the bottlenecks are. Make the decision, write it down, and spend the saved weeks on the product.