Runtime Modes trong Next.js¶
Hai loại Runtime¶
Next.js hỗ trợ 2 runtime environments:
┌─────────────────────────────────────────────────────────────┐
│ Next.js Application │
├─────────────────────────────┬───────────────────────────────┤
│ Node.js Runtime │ Edge Runtime │
├─────────────────────────────┼───────────────────────────────┤
│ • Full Node.js APIs │ • Web Standard APIs │
│ • fs, path, crypto... │ • fetch, Request, Response │
│ • npm packages (all) │ • npm packages (subset) │
│ • Cold start possible │ • Near-zero cold start │
│ • Regional deployment │ • Global edge deployment │
│ • Memory: 1-4GB │ • Memory: 128MB │
│ • Timeout: 60s+ │ • Timeout: 30s │
└─────────────────────────────┴───────────────────────────────┘
Node.js Runtime¶
Đặc điểm¶
- Full access to Node.js APIs
- Chạy trên server regions (us-east-1, etc.)
- Cold start 200-500ms
- Unlimited npm packages
Khi nào dùng¶
- Heavy computation
- File system operations
- Native npm packages (bcrypt, sharp)
- Long-running tasks
// app/api/heavy/route.ts
// Default: Node.js runtime
import fs from 'fs';
import { hash } from 'bcrypt';
export async function POST(request: Request) {
const { password } = await request.json();
// Node.js specific: bcrypt native module
const hashed = await hash(password, 10);
// Node.js specific: file system
fs.writeFileSync('/tmp/log.txt', 'logged');
return Response.json({ hashed });
}
Edge Runtime¶
Đặc điểm¶
- Web Standard APIs only
- Chạy tại 300+ edge locations
- Near-zero cold start (~0-5ms)
- Limited npm packages
- 128MB memory limit
- 30s timeout (free), 15min (paid)
Khi nào dùng¶
- Low latency required
- Simple data transformations
- Authentication/Authorization
- API Gateway/Proxy
- A/B testing, personalization
// app/api/fast/route.ts
export const runtime = 'edge'; // Enable Edge runtime
export async function GET(request: Request) {
// Web Standard APIs
const url = new URL(request.url);
const id = url.searchParams.get('id');
// Fetch external API
const data = await fetch(`https://api.example.com/${id}`);
return Response.json(await data.json());
}
So sánh chi tiết¶
| Tiêu chí | Node.js | Edge |
|---|---|---|
| Cold start | 200-500ms | ~0-5ms |
| Location | Regions | Global edge |
| Memory | 1-4GB | 128MB |
| Timeout | 60s+ | 30s |
| File system | Yes | No |
| Native modules | Yes | No |
| WebSocket | Yes | Limited |
| Streaming | Yes | Yes |
| Supabase client | Yes | Yes |
Cloudflare Workers = Edge Runtime¶
Tại sao Cloudflare dùng Edge?¶
Traditional Server:
User (Tokyo) ──── 200ms ────▶ Server (US) ──── 200ms ────▶ User
Edge Runtime:
User (Tokyo) ──── 10ms ────▶ Edge (Tokyo) ──── 10ms ────▶ User
Cloudflare Workers limitations¶
// ❌ KHÔNG hoạt động trên Workers
import fs from 'fs'; // No file system
import { hash } from 'bcrypt'; // Native module
import sharp from 'sharp'; // Native module
// ✅ Hoạt động trên Workers
import { createClient } from '@supabase/supabase-js'; // Pure JS
import { z } from 'zod'; // Pure JS
import dayjs from 'dayjs'; // Pure JS
Cấu hình Runtime¶
Per-route configuration¶
// app/api/edge-route/route.ts
export const runtime = 'edge';
export async function GET() {
return Response.json({ runtime: 'edge' });
}
Per-page configuration¶
// app/dashboard/page.tsx
export const runtime = 'edge';
export default function Dashboard() {
return <div>Dashboard</div>;
}
Global configuration (next.config.js)¶
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
// Force all routes to use edge runtime
experimental: {
runtime: 'edge',
},
};
module.exports = nextConfig;
Hybrid Approach¶
Best of both worlds¶
┌─────────────────────────────────────────────────────────┐
│ Next.js Application │
├────────────────────────┬────────────────────────────────┤
│ Edge Runtime │ Node.js Runtime │
│ (Cloudflare) │ (External API) │
├────────────────────────┼────────────────────────────────┤
│ • SSR Pages │ • Image processing │
│ • API Routes │ • PDF generation │
│ • Auth middleware │ • Heavy computation │
│ • Data fetching │ • Native modules │
└────────────────────────┴────────────────────────────────┘
│ │
▼ ▼
Cloudflare Supabase Edge
Workers Functions
Ví dụ: Image processing¶
// Edge: Handle request, delegate heavy work
// app/api/process-image/route.ts
export const runtime = 'edge';
export async function POST(request: Request) {
const formData = await request.formData();
const file = formData.get('file');
// Delegate to Supabase Edge Function (Deno runtime)
const result = await fetch(
'https://xxx.supabase.co/functions/v1/process-image',
{
method: 'POST',
body: file,
}
);
return result;
}
Hands-on Exercise¶
Tạo route với cả 2 runtime¶
// 1. Edge route
// app/api/edge/route.ts
export const runtime = 'edge';
export async function GET() {
return Response.json({
runtime: 'edge',
timestamp: Date.now(),
});
}
// 2. Node.js route (default)
// app/api/node/route.ts
export async function GET() {
return Response.json({
runtime: 'nodejs',
nodeVersion: process.version,
});
}
Bài tập: So sánh response time của 2 routes
Tổng kết¶
Key Points¶
- Edge Runtime = Web Standard APIs only
- Cloudflare Workers = Edge Runtime
- Chọn Edge khi: Low latency, simple logic
- Chọn Node.js khi: Native modules, heavy processing
Decision Flow¶
Cần native modules? ────▶ Node.js
│
▼
Cần file system? ────▶ Node.js
│
▼
Heavy computation? ────▶ Node.js (hoặc delegate)
│
▼
└────▶ Edge Runtime ✓
Q&A¶
- Dự án của bạn cần native modules nào?
- Latency quan trọng như thế nào?
- Có use case nào cần Node.js runtime không?