deep-dive2025-04-25·10 min·109/348

Vercel Edge Runtime과 Node.js Runtime 차이

Vercel Edge Runtime과 Node.js Runtime의 차이점, 사용 사례, 성능 특성을 비교 분석합니다.

Vercel Edge Runtime과 Node.js Runtime 차이

Introduction

Vercel은 두 가지 주요 런타임을 제공합니다: Edge Runtime과 Node.js Runtime. 각각의 런타임은 다른 특성과 사용 사례를 가지고 있으며, 적절한 선택은 애플리케이션 성능에 큰 영향을 미칩니다. 이 글에서는 두 런타임의 차이점을 깊이 분석하고, 어떤 상황에서 어떤 런타임을 선택해야 하는지 알아보겠습니다.

Environment

  • Vercel 프로젝트 (Next.js 14+)
  • Edge Runtime: V8 엔진 기반
  • Node.js Runtime: Node.js 18+
  • 글로벌 CDN: Vercel Edge Network

Problem

어떤 런타임을 선택해야 할지 혼란스러운 상황이 많습니다:

// 같은 API 엔드포인트에서 다른 런타임 사용 시 발생하는 문제
Error: Module not found: Can't resolve 'fs'
Error: Module not found: Can't resolve 'path'
Error: Node.js APIs are not available in Edge Runtime

Analysis

Edge Runtime

Edge Runtime은 V8 엔진 기반의 경량 런타임으로, 전 세계 Vercel Edge 노드에서 실행됩니다.

특징:

  • Cold start 시간: ~5ms
  • 실행 시간 제한: 30초 (Hobby), 300초 (Pro)
  • 글로벌 배포: 모든 Edge 노드에서 실행
  • 제한된 Node.js API 지원
  • Web API 표준 준수

지원하는 기능:

// 지원되는 기능
fetch()          // HTTP 요청
Response/Request // Web API
URL/URLPattern   // URL 처리
crypto           // 암호화
TextEncoder/Decoder // 텍스트 처리

// 지원되지 않는 기능
fs              // 파일 시스템
path            // 경로 처리
child_process   // 프로세스 관리
require()       // CommonJS 모듈

Node.js Runtime

Node.js Runtime은 전통적인 Node.js 환경에서 실행됩니다.

특징:

  • Cold start 시간: ~250ms
  • 실행 시간 제한: 10초 (Hobby), 60초 (Pro)
  • 특정 리전에서 실행
  • 전체 Node.js API 지원
  • npm 패키지 호환성

지원하는 기능:

// 모든 Node.js API 지원
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const { createHash } = require('crypto');

// npm 패키지 사용 가능
const { PrismaClient } = require('@prisma/client');
const redis = require('redis');

Solution

1. 런타임 선택 기준

// Edge Runtime이 적합한 경우
export const runtime = 'edge';

// 데이터베이스 연결이 필요한 경우
// Node.js Runtime이 적합
export const runtime = 'nodejs';

// 미들웨어에서의 사용
export const config = {
  runtime: 'edge'
};

2. Edge Runtime 사용 예시

// app/api/edge-endpoint/route.js
export const runtime = 'edge';

export async function GET(request) {
  const { searchParams } = new URL(request.url);
  const query = searchParams.get('q');
  
  // 외부 API 호출
  const response = await fetch(`https://api.example.com/search?q=${query}`);
  const data = await response.json();
  
  return Response.json(data);
}

3. Node.js Runtime 사용 예시

// app/api/data-endpoint/route.js
export const runtime = 'nodejs';

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export async function GET(request) {
  const users = await prisma.user.findMany({
    take: 10,
    orderBy: { createdAt: 'desc' }
  });
  
  return Response.json(users);
}

4. 하이브리드 접근법

// lib/optimized-fetch.js
export async function optimizedFetch(url, options = {}) {
  // Edge Runtime에서 실행되는 유틸리티 함수
  const controller = new AbortController();
  const timeout = options.timeout || 5000;
  
  const timeoutId = setTimeout(() => controller.abort(), timeout);
  
  try {
    const response = await fetch(url, {
      ...options,
      signal: controller.signal
    });
    clearTimeout(timeoutId);
    return response;
  } catch (error) {
    clearTimeout(timeoutId);
    throw error;
  }
}

5. 미들웨어에서의 런타임 선택

// middleware.js
import { NextResponse } from 'next/server';

export const config = {
  matcher: ['/api/:path*']
};

export function middleware(request) {
  const origin = request.headers.get('origin');
  
  // CORS 처리
  const response = NextResponse.next();
  response.headers.set('Access-Control-Allow-Origin', origin);
  response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  
  return response;
}

6. 성능 비교 테스트

// scripts/benchmark-runtimes.js
async function testEdgeRuntime() {
  const start = Date.now();
  
  const response = await fetch('https://your-app.vercel.app/api/edge-test');
  await response.json();
  
  return Date.now() - start;
}

async function testNodeRuntime() {
  const start = Date.now();
  
  const response = await fetch('https://your-app.vercel.app/api/node-test');
  await response.json();
  
  return Date.now() - start;
}

// 벤치마크 실행
async function runBenchmark() {
  const iterations = 10;
  const edgeTimes = [];
  const nodeTimes = [];
  
  for (let i = 0; i < iterations; i++) {
    edgeTimes.push(await testEdgeRuntime());
    nodeTimes.push(await testNodeRuntime());
  }
  
  const edgeAvg = edgeTimes.reduce((a, b) => a + b) / iterations;
  const nodeAvg = nodeTimes.reduce((a, b) => a + b) / iterations;
  
  console.log(`Edge Runtime Average: ${edgeAvg}ms`);
  console.log(`Node.js Runtime Average: ${nodeAvg}ms`);
}

Lessons Learned

  1. Cold Start 시간: Edge Runtime은 훨씬 빠른 cold start를 제공합니다.
  2. API 제한: Edge Runtime은 제한된 API만 지원하므로, 사용 전 호환성을 확인해야 합니다.
  3. 글로벌 배포: Edge Runtime은 전 세계에서 실행되어 더 빠른 응답 시간을 제공합니다.
  4. 메모리 제한: Edge Runtime은 메모리 제한이 더 엄격합니다.
  5. 데이터베이스 연결: 데이터베이스 연결이 필요한 경우 Node.js Runtime을 선택해야 합니다.

This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.