Bỏ qua

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

  1. Edge Runtime = Web Standard APIs only
  2. Cloudflare Workers = Edge Runtime
  3. Chọn Edge khi: Low latency, simple logic
  4. 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

  1. Dự án của bạn cần native modules nào?
  2. Latency quan trọng như thế nào?
  3. Có use case nào cần Node.js runtime không?