Deployment และ Self-Hosting
ไอเดียในหนึ่งประโยค
หัวข้อที่มีชื่อว่า “ไอเดียในหนึ่งประโยค”เรา deploy บน Vercel แบบ zero-config ได้ หรือจะ self-host เป็น Node server หลัง CDN ก็ได้ แต่พอรันมากกว่าหนึ่ง instance เมื่อไร caching และ ISR ต้องมี shared cache handler เพื่อให้ทุก instance ตรงกัน
Vercel versus self-hosting
หัวข้อที่มีชื่อว่า “Vercel versus self-hosting”Vercel ตรวจเจอ Next.js app แล้วจัดการ build, CDN, image optimization และ runtime แบบ Edge/Node ให้โดยไม่ต้อง config self-hosting ให้เราคุมเองทั้งหมด เรา build แล้วรัน next start (Node server ที่อยู่ยาว) เอง โดยปกติวางไว้หลัง CDN ที่ cache static asset
# Self-hosting: build once, then run a long-lived Node servernext buildnext start -p 3000A minimal Docker image with output standalone
หัวข้อที่มีชื่อว่า “A minimal Docker image with output standalone”ตั้ง output: 'standalone' แล้ว Next.js จะ trace ว่า server ต้องใช้ไฟล์ไหนบ้างแล้ว copy เข้า .next/standalone เราได้ image เล็ก ๆ ที่ ship ได้โดยไม่ต้องมี node_modules
import type { NextConfig } from 'next'
const nextConfig: NextConfig = { output: 'standalone',}
export default nextConfig# Minimal runtime image — copy only the traced standalone outputFROM node:20-alpineWORKDIR /appCOPY --from=builder /app/.next/standalone ./COPY --from=builder /app/.next/static ./.next/staticCOPY --from=builder /app/public ./public# standalone ships its own server.js — do NOT use "next start" hereCMD ["node", "server.js"]Caching and ISR across instances
หัวข้อที่มีชื่อว่า “Caching and ISR across instances”ISR, full-route cache และ revalidateTag เขียนลง cache ทั้งหมด บน instance เดียว filesystem cache แบบ default ก็พอ แต่พอรันหลาย instance แต่ละตัวมี local cache ของตัวเอง เพราะฉะนั้น revalidateTag บน pod หนึ่งจะทิ้งตัวอื่นให้ค้างอยู่ ทางแก้คือ shared cache handler (หนุนหลังด้วย Redis หรือคล้าย ๆ กัน) ที่ทุก instance อ่านและเขียนร่วมกัน
// next.config.ts — shared cache for multi-instance self-hostingimport type { NextConfig } from 'next'
const nextConfig: NextConfig = { cacheHandler: require.resolve('./cache-handler.js'), cacheMaxMemorySize: 0, // disable the in-memory cache; use the shared handler}
export default nextConfigพอมี shared handler การเรียก revalidateTag('products') ใน Server Action จะ invalidate entry ให้ทุก instance พร้อมกัน และเลือกต่อ route ด้วยว่าจะใช้ Node runtime (Node API ครบ) หรือ Edge runtime (เร็วแต่ API จำกัด) ตามที่แต่ละ route ต้องใช้จริง
Go-live checklist
หัวข้อที่มีชื่อว่า “Go-live checklist”นี่คือจุดสุดท้าย เพราะฉะนั้นรวบทั้งคอร์สเข้าด้วยกันก่อน ship
- เก็บ data fetching ไว้ใน Server Components mark leaf เป็น
'use client'เฉพาะตอนที่ต้อง interactive จริง ๆ - เลือก rendering mode ต่อ route อย่างตั้งใจ ทั้ง static, dynamic หรือ ISR แล้ว confirm ว่าแต่ละตัวทำงานตามที่คาดใน production build
- เข้าใจ caching layer ของตัวเอง (request memoization, Data Cache, full-route cache) แล้ววาง shared cache handler ก่อน scale เกินหนึ่ง instance
- mutate ผ่าน Server Actions แล้วเรียก
revalidateTag/revalidatePathเพื่อให้ cache ถูกต้องหลัง write - gate route ที่ป้องกันไว้ด้วย optimistic middleware redirect และ Data Access Layer check ควบคู่กัน
- เก็บ secret แบบไม่มี prefix ไว้ใน
.env.localเปิดเผยเฉพาะค่าNEXT_PUBLIC_
graph TD A["CDN"] --> B["Instance 1 (next start)"] A --> C["Instance 2 (next start)"] B --> D["Shared cache handler (Redis)"] C --> D D --> E["revalidateTag invalidates all instances"]