TanStack Start vs Next.js (2026) — แอปเดียวกัน benchmark จริงTanStack Start vs Next.js (2026) — same app, real benchmarks
← → เปลี่ยนหน้า · L สลับภาษา · F เต็มจอ← → slides · L language · F fullscreen
1 / 12

สรุปบทความจาก fabwaseem.com · Waseem Anjum · 17 ตุลาคม 2026Article summary · fabwaseem.com · Waseem Anjum · Oct 17, 2026

TanStack Start vs Next.js

สร้างแอปเดียวกันด้วยทั้งสอง framework แล้ววัดจริงบน 2 cores: ฝั่ง server Start รับ request ได้มากกว่า 2.9–8.6 เท่า ส่ง JS น้อยกว่า 20% และ build เร็วกว่า 3.9 เท่า ส่วน Next.js ชนะแค่หน้า staticThe same app built in both frameworks and measured on 2 cores: on the server Start handled 2.9–8.6× more requests, shipped 20% less JS and built 3.9× faster. Next.js won only on the static page.

TanStack Start 1.169.3 · Next.js 16.4.2 · Node 24.22

fabwaseem.com/blog

01 · บริบท01 · Context

Start 1.0 stable แล้ว และมองเรื่อง component คนละแบบกับ Next.jsStart 1.0 is stable, and it thinks about components differently from Next.js

TanStack Start เป็น full-stack React framework ที่ต่อยอดจาก TanStack Router มาพร้อม SSR, streaming, server function แบบ typed, server route สำหรับจัดการ HTTP ตรง ๆ และ middleware ใช้ Vite (หรือ Rsbuild) เป็นตัว build ออก 1.0 stable เมื่อ 13 ต.ค. 2026 (@tanstack/react-start 1.169.0)TanStack Start is a full-stack React framework built on TanStack Router, with SSR, streaming, typed server functions, server routes for raw HTTP, and middleware. It builds with Vite (or Rsbuild). Version 1.0 went stable on October 13, 2026 (@tanstack/react-start 1.169.0).

Next.js App Router

page และ layout เป็น React Server Component โดย default ถ้าต้องการโค้ดฝั่ง client ต้องใส่ "use client" เองPages and layouts are React Server Components by default; client code is opt-in with "use client"

TanStack Start

ทุก component เป็น React component ธรรมดา render บน server แล้ว hydrate ฝั่ง client อยากให้อะไรรันบน server ก็ประกาศชัด ๆ ผ่าน createServerFn() หรือ route loader ส่วน Server Component ยัง experimental และปิดอยู่โดย defaultEvery component is an ordinary React component that renders on the server and hydrates on the client. Server work is explicit through createServerFn() or a route loader. Server Components exist but are experimental and off by default.

01 · วิธีทดสอบ01 · Method

แอปร้านค้าเดียวกัน 4 route วัดบน server 2 coresThe same store, 4 routes, measured on a 2-core server

Home

มีแค่หัวข้อกับลิงก์ Next.js prerender เป็น static HTML ส่วน Start render ใหม่ทุก requestA heading and a link. Next.js prerenders it as static HTML; Start renders it on every request

Product list

สินค้า 100 ชิ้น SSR ทุก request ใส่ timestamp ไว้กันไม่ให้ cache ได้ทั้งคู่100 products server-rendered on every request, with a timestamp so neither side can cache it

Product page

สินค้า 1 ชิ้น + ปุ่ม Add to cart ที่นับจำนวนฝั่ง client ทั้งคู่เลยต้อง hydrateOne product plus a client-side Add to cart counter, so both must hydrate

JSON API

คืนสินค้า 20 ชิ้นเป็น JSON ฝั่ง Next.js ใช้ route handler แบบ force-dynamic ฝั่ง Start ใช้ server routeReturns 20 products. A force-dynamic route handler in Next.js, a server route in Start

เวอร์ชันVersions

Next.js 16.4.2 + Turbopack + React 19.3.0 vs Start 1.169.3 + Vite 8.3.4 + Nitro + React 19.3.1 ทั้งคู่ใช้ Tailwind 4 รันบน Node 24.22 แบบ productionNext.js 16.4.2 + Turbopack + React 19.3.0 vs Start 1.169.3 + Vite 8.3.4 + Nitro + React 19.3.1, both with Tailwind 4 on Node 24.22 in production mode

ฝั่ง serverServer side

pin server ไว้ที่ 2 cores ด้วย taskset แล้วยิง load ด้วย oha จากอีก 6 cores (64 connections นาน 10 วินาที warm-up ก่อน 4 วินาที) เอาค่า median จาก 3 รอบServer pinned to 2 cores with taskset; oha load from 6 other cores (64 connections for 10 s after a 4 s warm-up), median of 3 runs

ฝั่ง clientClient side

ใช้ Playwright + Chromium วัดขนาด script (gzip) และเวลาตั้งแต่เปิดหน้าจนปุ่มกดได้ โดย throttle CPU ลง 4 เท่า เอาค่า median จาก 6 รอบPlaywright + Chromium measured gzipped script bytes and time from navigation to a working button at 4× CPU throttling, median of 6 runs

นี่เป็นแอปจำลองเล็ก ๆ ไม่ใช่แอปของคุณ ของจริง database, auth และ caching มักกินเวลามากกว่านี้ ให้มองตัวเลขพวกนี้เป็น overhead ของตัว framework ล้วน ๆThis is a small synthetic store, not your app. Real database, auth and caching usually dominate; read these numbers as the cost of the framework layer itself.

02 · ฝั่ง server02 · Server

route ที่ต้อง render ทุก request Start เร็วกว่า 2.9–8.6 เท่าOn every per-request route, Start was 2.9–8.6× faster

8.6×

JSON API route

18,515 vs 2,165 req/s server route ของ Start แทบจะเป็น handler เปล่า ๆ บน Nitro แต่ทุก request ของ Next.js ต้องวิ่งผ่าน Next server กับ router ทั้งชุด18,515 vs 2,165 req/s. Start’s server route is close to a bare handler on Nitro, while every Next.js request goes through the full Next server and router

รายการMetricNext.jsStartผลต่างDifference
list 100 ชิ้น (SSR)List, 100 items (SSR)220 req/s637 req/sStart 2.9×
product page (SSR)512 req/s2,341 req/sStart 4.6×
JSON API route2,165 req/s18,515 req/sStart 8.6×
p99 ของหน้า listp99, list page754 ms194 msต่ำกว่า 3.9×3.9× lower
memory ตอน idleMemory at idle94 MB60 MBStart −36%

02 · ฝั่ง server02 · Server

Next.js ชนะแค่หน้า static ที่ prerender ไว้Next.js won only on its prerendered static page

Next.js · static HTML

3,220 req/s

ส่งไฟล์ HTML ที่ prerender ไว้ตรง ๆ ไม่ต้อง render React เลยServes the prerendered HTML file, no React rendering at all

TanStack Start · SSR ทุก requestTanStack Start · SSR on every request

2,920 req/s

render ด้วย React ใหม่ทุกครั้ง แต่ยังตามหลังแค่ 10%Renders with React every time, yet only 10% behind

ทำไม Next.js ถึงช้ากว่าเมื่อต้อง SSRWhy Next.js is slower when it has to SSR

ผู้เขียนมองว่า Next.js ทำงานต่อ request เยอะกว่า: ต้อง render Server Component tree ออกมาเป็น RSC payload ก่อน แล้วค่อย render HTML จาก payload นั้นอีกที แถมฝัง payload ลงในหน้าด้วย HTML ของหน้า list 100 ชิ้นเลยหนัก 92 KB (Start 60 KB; gzip แล้ว 8.5 vs 6.4 KB) ส่วน memory ตอน load สูงสุด Next.js 504 MB vs Start 363 MBThe author’s reading: Next.js does more work per request. It renders the Server Component tree to an RSC payload, then renders HTML from it, and embeds the payload in the page. The 100-item list page was 92 KB of HTML vs 60 KB for Start (8.5 vs 6.4 KB gzipped), and peak memory under load was 504 MB vs 363 MB.

อะไรที่ prerender หรือ cache ได้ (เช่นผ่าน "use cache") จะข้ามต้นทุนตรงนี้ไปเกือบหมด ถ้าแอปคุณส่วนใหญ่เป็น content ที่ cache ได้ ตัวเลขฝั่ง server ด้านบนก็แทบไม่มีผลAnything you can prerender or cache (for example with "use cache") skips most of that per-request cost. If your app is mostly cacheable content, the server numbers above matter far less.

03 · ฝั่ง client03 · Client

ฝั่ง client Start นำอยู่ แต่ไม่ได้ทิ้งห่างOn the client Start leads, but not by much

−20%

client JS บนหน้า /productsclient JS on /products

จาก 135 KB เหลือ 109 KB (gzip) ส่วนต่างราว 26 KB คือ runtime ของตัว framework เพราะเนื้อส่วนใหญ่ของทั้งคู่คือ React กับ React DOM135 KB down to 109 KB gzipped. The ~26 KB difference is the framework runtime; most of both bundles is React and React DOM

รายการMetricNext.jsStartผลต่างDifference
client JS (gzip)135 KB / 7 ไฟล์135 KB / 7 files109 KB / 3 ไฟล์109 KB / 3 filesStart −20%
ปุ่มกดได้ (throttle CPU 4×)Button interactive (4× CPU throttle)324 ms289 msStart −35 ms
เปลี่ยนหน้า list → productNavigation list → product182 ms160 msStart −22 ms
request ต่อการเปลี่ยนหน้าRequests per navigation~102Start น้อยกว่าFewer on Start

ในแอปจริงที่ใช้ component library ใหญ่ ๆ โค้ดของคุณเองจะหนักกว่าส่วนต่าง 26 KB นี้มากIn a real app with a large component library, your own code will outweigh this 26 KB

03 · Build และ deploy03 · Build and deploy

build เร็วกว่า 3.9 เท่า และ deploy เล็กกว่า 27 เท่า3.9× faster builds and a 27× smaller deploy

production build

Next.js

4.86 s

Start

1.26 s

เร็วกว่า 3.9× ต่อให้บวกเวลา tsc เข้าไปก็ยังเร็วกว่าราว 1.7×3.9× faster; still about 1.7× faster with a separate tsc run added

dev server ถึงหน้าแรกdev server to first page

Next.js

2.96 s

Start

1.52 s

เร็วกว่า 1.9× ทั้งตอน cold และ warm1.9× faster, cold and warm

deploy output

Next.js standalone

38 MB

Start (Nitro)

1.4 MB

Next.js copy node_modules ที่ต้องใช้ติดไปด้วย ส่วน Start bundle ทุกอย่างรวมเป็นก้อนเดียวNext.js traces and copies the node_modules it needs; Start bundles everything into one output

node_modules ที่ติดตั้งinstalled node_modules

Next.js

354 MB

Start

152 MB

เล็กกว่ากันเกือบครึ่งUnder half the size

ใน Docker image ส่วนต่างตรงนี้มีผลจริง แต่ก็เล็กเมื่อเทียบกับขนาดของ Node base imageIn a Docker image the difference is real, but small next to a Node base image

04 · Developer experience04 · Developer experience

ใช้งานจริงวันต่อวัน ต่างกันตรงไหนWhat’s different day to day

เรื่องAreaNext.js 16.4TanStack Start 1.0
โหลดข้อมูลData loadingfetch ใน async Server ComponentFetch inside async Server Componentsroute loader + server function (มักใช้คู่กับ TanStack Query)Route loaders + server functions, usually with TanStack Query
โค้ดฝั่ง serverServer codeServer Action และ route handlerServer Actions and route handlerscreateServerFn() ใส่ validator ได้ มี middleware ที่รันทั้ง client และ servercreateServerFn() with validators, and middleware that runs on client and server
type safetytypedRoutes ต้องเปิดเอง คุมได้แค่ลิงก์ ไม่ validate search paramsOpt-in typedRoutes: covers links but doesn’t validate search paramsrouter gen type ให้ทุก path, param และ search param ลิงก์พังเมื่อไหร่ก็เป็น type error ทันทีThe router generates types for every path, param and search param; a broken link is a type error
cachingมี cache ในตัว framework: Cache Components, "use cache", cacheLifeBuilt-in framework cache: Cache Components, "use cache", cacheLifeไม่มี server cache ในตัว ต้องใช้ HTTP header, CDN หรือ store ของตัวเองNo built-in server cache; use HTTP headers, a CDN or your own store
built-insnext/image, next/font, metadata API และตัวอย่างให้ดูเพียบnext/image, next/font, metadata API and a huge set of examplesต้องจัดการ image กับ font เองBring your own image and font handling
hostingลื่นสุดบน Vercel แต่รันที่ไหนก็ได้ถ้ามี Node หรือ DockerBest on Vercel; runs anywhere with Node or Dockerdeploy ผ่าน Nitro หรือ plugin ได้ทั้ง Node, Bun, Cloudflare Workers, Netlify, Vercel, RailwayDeploys via Nitro or plugins to Node, Bun, Cloudflare Workers, Netlify, Vercel, Railway

การไม่มี cache ในตัวทำให้ Start เข้าใจง่ายกว่า แต่ถ้าทำเว็บ content ก็ต้องทำเองเพิ่มNo framework cache makes Start simpler to reason about, but it’s more work for content sites

05 · ตัดสินใจ05 · Deciding

ควรย้ายจาก Next.js ไป TanStack Start ไหมShould you switch from Next.js to TanStack Start?

เลือก TanStack Start เมื่อPick TanStack Start if

  • แอปที่ต้อง render ทุก request เช่น dashboard, SaaS, internal toolYour app renders per request: dashboards, SaaS, internal tools
  • อยากได้ typed route และ server function ที่ชัดเจนYou want typed routes and explicit server functions
  • ชอบ Vite หรืออยาก deploy บน Cloudflare Workers, VPS เล็ก ๆYou like Vite, or want Cloudflare Workers or a small VPS
  • ใช้ TanStack Query, Router หรือ Table อยู่แล้วYou already use TanStack Query, Router or Table

อยู่กับ Next.js เมื่อStay with Next.js if

  • เว็บส่วนใหญ่เป็น content ที่ prerender หรือ cache ได้Your site is mostly prerendered or cacheable content
  • พึ่ง RSC, next/image, next/font หรือ metadata API อยู่You rely on RSC, next/image, next/font or the metadata API
  • ตัวอย่าง template และการหาคนร่วมทีม สำคัญกว่าความเร็วดิบExamples, templates and hiring matter more than raw speed
  • host บน Vercel และอยากใช้ integration ของมันYou host on Vercel and want its integration

แอป Next.js ที่รันดีอยู่แล้ว ไม่ต้อง rewrite เพราะตัวเลขพวกนี้ ลอง cache ให้สุดก่อน แต่ถ้าเริ่มแอป interactive ใหม่ Start 1.0 ถือเป็นตัวเลือกหลักได้แล้วDon’t rewrite a healthy Next.js app for these numbers; cache what you can first. For a new interactive app, Start 1.0 is now a serious default.

06 · การย้าย06 · Migrating

แนวทางย้ายจาก Next.js มา Start แบบคร่าว ๆ 7 ขั้นA rough 7-step path from Next.js to Start

1

ย้ายไฟล์ route จาก app/ ไป src/routes/ แล้วใช้ createFileRoute ส่วน dynamic segment เปลี่ยนจาก [id] เป็น $idMove app/ routes to src/routes/ files using createFileRoute; dynamic segments change from [id] to $id

2

เปลี่ยนการ fetch ใน async Server Component เป็น route loader ที่เรียก createServerFn()Replace data fetching in async Server Components with a route loader that calls createServerFn()

3

ลบ "use client" ทิ้งให้หมด เพราะใน Start ทุก component เป็น component ปกติRemove every "use client" directive; in Start every component is a normal component

4

เปลี่ยน route handler เป็น server route แบบ server: { handlers: { GET } }Turn route handlers into server routes with server: { handlers: { GET } }

5

เปลี่ยน Server Action เป็น server function แบบ POST แล้วใส่ input validatorReplace Server Actions with POST server functions and add an input validator

6

เปลี่ยน next/link เป็น Link ของ TanStack Router (to + typed params) ส่วน next/image กับ next/font ใช้ component ของตัวเองหรือแท็ก HTML ธรรมดาReplace next/link with TanStack Router’s Link (to + typed params), and next/image and next/font with your own components or plain tags

7

เพิ่ม Nitro หรือ hosting plugin ใน vite.config.ts ตามปลายทางที่จะ deployAdd Nitro (or a hosting plugin) to vite.config.ts for your deploy target

ลองย้าย route ที่เป็นตัวแทนสัก 1 เส้นให้จบครบทั้ง flow (รวม auth และ mutation) ก่อน แล้วค่อยตัดสินใจย้ายทั้งแอปMigrate one representative route end to end first, auth and a mutation included, before committing the whole app

07 · ข้อผิดพลาดที่พบบ่อย07 · Common mistakes

5 เรื่องที่ทำให้ผลเทียบเพี้ยน5 things that skew the comparison

เทียบ static กับ SSRComparing static with SSR

เอาหน้า static ของ Next.js ไปเทียบกับหน้า SSR ของ Start แล้วบอกว่า Next เร็วกว่า ต้องใช้โหมด render เดียวกันทั้งคู่ หรือไม่ก็ระบุให้ชัดเหมือนที่ผู้เขียนทำกับหน้า homePutting a static Next.js page against an SSR Start page and calling Next faster. Use the same rendering mode on both sides, or report it, as the author did for the home page

ลืม copy .next/staticForgetting to copy .next/static

ถ้าไม่ copy โฟลเดอร์นี้ไปไว้ใน standalone ตัว server จะไม่ส่ง client asset ออกมา hydration ก็ไม่ทำงานโดยไม่มี error อะไรเลย ผู้เขียนเจอ timeout 30 วินาทีเพราะเรื่องนี้Without it, the standalone server doesn’t serve client assets and hydration silently never happens; the author hit a 30-second timeout from exactly this

benchmark ใน dev modeBenchmarking dev mode

ต้อง build ก่อนแล้วรันด้วย NODE_ENV=production เสมอAlways build and run with NODE_ENV=production

load generator แย่ง core กับ serverLoad generator sharing cores with the server

ถ้าไม่ pin แยก core กัน ตัวเลขที่ได้จะสะท้อนการแย่ง CPU มากกว่าประสิทธิภาพของ frameworkPin them apart, or your numbers mostly measure CPU contention rather than the framework

ปล่อย devtools ค้างใน productionLeaving devtools in production

เช็กให้ชัวร์ว่า router devtools กับ query devtools ไม่หลุดไปอยู่ใน client bundleCheck that router and query devtools aren’t in the client bundle

gotcha แถม: เขียน next.config.ts ทับแล้ว turbopack.rules ของ Tailwind 4 หาย CSS เลยว่างเปล่า แถม Tailwind compiler หลุดเข้า client bundle จนบวมจาก 135 KB เป็น 280 KBBonus gotcha: overwriting next.config.ts dropped the Tailwind 4 turbopack.rules entry, so the CSS came out empty and the Tailwind compiler landed in the client bundle: 280 KB instead of 135 KB

08 · สรุป08 · Summary

สรุปใน 3 ข้อThree takeaways

1

ฝั่ง server Start เร็วกว่า 2.9–8.6 เท่าในทุก route ที่ต้อง render ทุก request, p99 ต่ำกว่า 3.9 เท่า และกิน memory น้อยกว่า 36%On the server, Start was 2.9–8.6× faster on every per-request route, with 3.9× lower p99 and 36% less memory

2

Start ส่ง JS น้อยกว่า 20%, build เร็วกว่า 3.9 เท่า, deploy เล็กกว่า 27 เท่า แต่ Next.js ชนะที่หน้า static และมี RSC, built-in กับ ecosystem ที่ใหญ่กว่าเยอะStart ships 20% less JS, builds 3.9× faster and deploys 27× smaller, but Next.js wins the static page and has RSC, built-ins and a much larger ecosystem

3

แอป interactive ที่ render ทุก request และอยากได้ typed routing เลือก Start ส่วนเว็บ content ที่ cache ได้ เลือก Next.js และแอป Next.js ที่รันดีอยู่แล้วก็ไม่จำเป็นต้อง rewriteChoose Start for interactive per-request apps with typed routing; choose Next.js for cacheable content. A healthy Next.js app doesn’t need a rewrite

แหล่งอ้างอิงSources

บทความต้นทาง: fabwaseem.com/blog/tanstack-start-vs-nextjs (Waseem Anjum, 17 ตุลาคม 2026)Original article: fabwaseem.com/blog/tanstack-start-vs-nextjs (Waseem Anjum, Oct 17, 2026)

ประกาศ Start 1.0: tanstack.com/blog/tanstack-start-1-0 · ตารางเทียบทางการ: tanstack.com/start/latest/docs/framework/react/start-vs-nextjsStart 1.0 announcement: tanstack.com/blog/tanstack-start-1-0 · Official comparison: tanstack.com/start/latest/docs/framework/react/start-vs-nextjs