Why we chose TanStack Start over Next.js
The unglamorous engineering decision that shaped every subsequent product decision — and why we would make it again.

Framework choice is the least interesting decision a startup makes and one of the most consequential. It shapes hiring, deployment, cost, and speed of iteration for years. When we started nctools we spent three weeks prototyping in Next.js, Remix, and TanStack Start. We picked TanStack Start. Here is why.
The requirement
nctools needed three things from a framework: fast page-load, strong routing primitives (nested routes, loaders, type-safe params), and an escape hatch for the moments when server-side rendering fights us.
All three frameworks meet those requirements. Next.js does so with the largest ecosystem, Remix with the tightest data-loading story, TanStack Start with the most flexible primitives. In prototyping, TanStack Start consistently produced the smallest bundle and the fastest development loop.
The escape hatch
Our tools ship large browser-only dependencies — pdfjs-dist, tesseract.js WebAssembly, docx, xlsx. None of those work under SSR. In Next.js this requires dynamic({ ssr: false }) wrappers everywhere. In TanStack Start, ClientOnly is a single component and the rest of the code stays plain. That difference is not a deal-breaker on its own, but it removes an entire category of production bugs.
File-based routing without the surprises
TanStack Router's file-based routing is deliberate. Dots in filenames map to slashes in URLs. Underscores mark layouts. Dollar signs mark params. No magic; nothing behaves unexpectedly. Coming from Next.js's App Router (which layers several conventions on top of each other), the clarity is refreshing.
// src/routes/tools.pdf-to-word.tsx
export const Route = createFileRoute("/tools/pdf-to-word")({
component: PdfToWord,
});Loader-first data
Every route can define a loader that runs before render. Combine it with TanStack Query and you get server-rendered, client-hydrated, cache-consistent data with no useEffect boilerplate. The pattern encourages you to think about data flow upfront instead of hacking it in later.
Bundle size
On our production build, the client entry is 68 KB gzipped for the shared framework code. Each route adds 4-15 KB on average. A comparable Next.js App Router build was 92 KB shared. Not a landslide, but noticeable in latency-sensitive markets.
What we gave up
A smaller ecosystem. Some Next.js patterns (parallel routes, intercepting routes) do not have exact equivalents. Some vendors ship 'Next.js' plugins with no TanStack equivalent. We have not missed anything essential in six months.
Would we choose it again?
Yes. If your product is largely CRUD-with-forms, Next.js will still be a fine choice and has more hires. If your product is any flavour of interactive tooling — dashboards, editors, browser-side compute — TanStack Start's flexibility pays dividends every week.
Marek Novák
Engineering Lead at nctools
Keep reading
Engineering
OCR in the browser: how Tesseract.js and WebAssembly changed everything
A deep look at running the world's most-used open-source OCR engine at 200+ MB of trained models directly in a user's tab.
ReadEngineering
Client-side PDF extraction with pdfjs-dist: a deep dive
Mozilla's pdfjs-dist library powers every PDF reader on the web. Here is what it does well, where the sharp edges are, and how we build on top of it.
ReadEngineering
Building a zero-upload SaaS: architecture notes
How we structure a product where 90 percent of user activity never touches our server, and what that means for our monitoring, billing and support.
Read